坚持使用 scrapy 抓取特定 table
Stuck scraping a specific table with scrapy
所以我要抓取的 table 可以在这里找到:http://www.betdistrict.com/tipsters
我正在关注标题为 'June Stats' 的 table。
这是我的蜘蛛:
from __future__ import division
from decimal import *
import scrapy
import urlparse
from ttscrape.items import TtscrapeItem
class BetdistrictSpider(scrapy.Spider):
name = "betdistrict"
allowed_domains = ["betdistrict.com"]
start_urls = ["http://www.betdistrict.com/tipsters"]
def parse(self, response):
for sel in response.xpath('//table[1]/tr'):
item = TtscrapeItem()
name = sel.xpath('td[@class="tipst"]/a/text()').extract()[0]
url = sel.xpath('td[@class="tipst"]/a/@href').extract()[0]
tipster = '<a href="' + url + '" target="_blank" rel="nofollow">' + name + '</a>'
item['Tipster'] = tipster
won = sel.xpath('td[2]/text()').extract()[0]
lost = sel.xpath('td[3]/text()').extract()[0]
void = sel.xpath('td[4]/text()').extract()[0]
tips = int(won) + int(void) + int(lost)
item['Tips'] = tips
strike = Decimal(int(won) / tips) * 100
strike = str(round(strike,2))
item['Strike'] = [strike + "%"]
profit = sel.xpath('//td[5]/text()').extract()[0]
if profit[0] in ['+']:
profit = profit[1:]
item['Profit'] = profit
yield_str = sel.xpath('//td[6]/text()').extract()[0]
yield_str = yield_str.replace(' ','')
if yield_str[0] in ['+']:
yield_str = yield_str[1:]
item['Yield'] = '<span style="color: #40AA40">' + yield_str + '%</span>'
item['Site'] = 'Bet District'
yield item
第一个变量(名称)出现列表索引超出范围错误。
但是,当我重写以 // 开头的 xpath 选择器时,例如:
name = sel.xpath('//td[@class="tipst"]/a/text()').extract()[0]
蜘蛛会跑,但会一遍又一遍地抓取第一个提示者。
我认为这与 table 没有 thead,但在 tbody 的第一个 tr 中包含 th 标签有关。
非常感谢任何帮助。
------------编辑----------
回应拉尔斯的建议:
我已尝试使用您的建议,但仍然出现列表超出范围的错误:
from __future__ import division
from decimal import *
import scrapy
import urlparse
from ttscrape.items import TtscrapeItem
class BetdistrictSpider(scrapy.Spider):
name = "betdistrict"
allowed_domains = ["betdistrict.com"]
start_urls = ["http://www.betdistrict.com/tipsters"]
def parse(self, response):
for sel in response.xpath('//table[1]/tr[td[@class="tipst"]]'):
item = TtscrapeItem()
name = sel.xpath('a/text()').extract()[0]
url = sel.xpath('a/@href').extract()[0]
tipster = '<a href="' + url + '" target="_blank" rel="nofollow">' + name + '</a>'
item['Tipster'] = tipster
yield item
此外,我假设通过这种方式做事,需要多个 for 循环,因为并非所有单元格都具有相同的 class?
我也试过在没有 for 循环的情况下做事,但在那种情况下,它再次多次只抓取第一个提示者 :s
谢谢
当你说
name = sel.xpath('td[@class="tipst"]/a/text()').extract()[0]
XPath 表达式以 td
开头,因此相对于变量 sel
中的上下文节点(即 tr
集合中的 tr
元素=] for
循环遍历的元素)。
但是当你说
name = sel.xpath('//td[@class="tipst"]/a/text()').extract()[0]
XPath 表达式以 //td
开头,即文档中任意位置的 select 所有 td
元素;这与 sel
无关,因此 for
循环的每次迭代的结果都是相同的。这就是为什么它一遍又一遍地抓取第一个提示者的原因。
为什么第一个 XPath 表达式因列表索引超出范围错误而失败?尝试一次对 XPath 表达式执行一个位置步骤,打印出结果,您很快就会发现问题所在。在这种情况下,似乎是因为 table[1]
的第一个 tr
child 没有 td
child(只有 th
child仁)。所以 xpath()
select 什么都没有, extract()
returns 是一个空列表,您尝试引用该空列表中的第一项,给出的列表索引超出范围错误。
要解决此问题,您可以将 for 循环 XPath 表达式更改为仅循环那些具有 td
children:
的 tr
元素
for sel in response.xpath('//table[1]/tr[td]'):
你可以变得更漂亮,需要 td
的右边 class:
for sel in response.xpath('//table[1]/tr[td[@class="tipst"]]'):
所以我要抓取的 table 可以在这里找到:http://www.betdistrict.com/tipsters
我正在关注标题为 'June Stats' 的 table。
这是我的蜘蛛:
from __future__ import division
from decimal import *
import scrapy
import urlparse
from ttscrape.items import TtscrapeItem
class BetdistrictSpider(scrapy.Spider):
name = "betdistrict"
allowed_domains = ["betdistrict.com"]
start_urls = ["http://www.betdistrict.com/tipsters"]
def parse(self, response):
for sel in response.xpath('//table[1]/tr'):
item = TtscrapeItem()
name = sel.xpath('td[@class="tipst"]/a/text()').extract()[0]
url = sel.xpath('td[@class="tipst"]/a/@href').extract()[0]
tipster = '<a href="' + url + '" target="_blank" rel="nofollow">' + name + '</a>'
item['Tipster'] = tipster
won = sel.xpath('td[2]/text()').extract()[0]
lost = sel.xpath('td[3]/text()').extract()[0]
void = sel.xpath('td[4]/text()').extract()[0]
tips = int(won) + int(void) + int(lost)
item['Tips'] = tips
strike = Decimal(int(won) / tips) * 100
strike = str(round(strike,2))
item['Strike'] = [strike + "%"]
profit = sel.xpath('//td[5]/text()').extract()[0]
if profit[0] in ['+']:
profit = profit[1:]
item['Profit'] = profit
yield_str = sel.xpath('//td[6]/text()').extract()[0]
yield_str = yield_str.replace(' ','')
if yield_str[0] in ['+']:
yield_str = yield_str[1:]
item['Yield'] = '<span style="color: #40AA40">' + yield_str + '%</span>'
item['Site'] = 'Bet District'
yield item
第一个变量(名称)出现列表索引超出范围错误。
但是,当我重写以 // 开头的 xpath 选择器时,例如:
name = sel.xpath('//td[@class="tipst"]/a/text()').extract()[0]
蜘蛛会跑,但会一遍又一遍地抓取第一个提示者。
我认为这与 table 没有 thead,但在 tbody 的第一个 tr 中包含 th 标签有关。
非常感谢任何帮助。
------------编辑----------
回应拉尔斯的建议:
我已尝试使用您的建议,但仍然出现列表超出范围的错误:
from __future__ import division
from decimal import *
import scrapy
import urlparse
from ttscrape.items import TtscrapeItem
class BetdistrictSpider(scrapy.Spider):
name = "betdistrict"
allowed_domains = ["betdistrict.com"]
start_urls = ["http://www.betdistrict.com/tipsters"]
def parse(self, response):
for sel in response.xpath('//table[1]/tr[td[@class="tipst"]]'):
item = TtscrapeItem()
name = sel.xpath('a/text()').extract()[0]
url = sel.xpath('a/@href').extract()[0]
tipster = '<a href="' + url + '" target="_blank" rel="nofollow">' + name + '</a>'
item['Tipster'] = tipster
yield item
此外,我假设通过这种方式做事,需要多个 for 循环,因为并非所有单元格都具有相同的 class?
我也试过在没有 for 循环的情况下做事,但在那种情况下,它再次多次只抓取第一个提示者 :s
谢谢
当你说
name = sel.xpath('td[@class="tipst"]/a/text()').extract()[0]
XPath 表达式以 td
开头,因此相对于变量 sel
中的上下文节点(即 tr
集合中的 tr
元素=] for
循环遍历的元素)。
但是当你说
name = sel.xpath('//td[@class="tipst"]/a/text()').extract()[0]
XPath 表达式以 //td
开头,即文档中任意位置的 select 所有 td
元素;这与 sel
无关,因此 for
循环的每次迭代的结果都是相同的。这就是为什么它一遍又一遍地抓取第一个提示者的原因。
为什么第一个 XPath 表达式因列表索引超出范围错误而失败?尝试一次对 XPath 表达式执行一个位置步骤,打印出结果,您很快就会发现问题所在。在这种情况下,似乎是因为 table[1]
的第一个 tr
child 没有 td
child(只有 th
child仁)。所以 xpath()
select 什么都没有, extract()
returns 是一个空列表,您尝试引用该空列表中的第一项,给出的列表索引超出范围错误。
要解决此问题,您可以将 for 循环 XPath 表达式更改为仅循环那些具有 td
children:
tr
元素
for sel in response.xpath('//table[1]/tr[td]'):
你可以变得更漂亮,需要 td
的右边 class:
for sel in response.xpath('//table[1]/tr[td[@class="tipst"]]'):