【问题标题】:Stuck scraping a specific table with scrapy卡住了用scrapy刮一个特定的桌子
【发布时间】:2015-06-11 01:11:00
【问题描述】:

所以我要抓取的表可以在这里找到:http://www.betdistrict.com/tipsters

我关注的是名为“六月统计”的表格。

这是我的蜘蛛:

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]

蜘蛛跑了,但一遍又一遍地刮掉第一个提示者。

我认为这与没有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 循环,因为并非所有单元格都具有相同的类?

我也尝试过不使用 for 循环来做事,但在这种情况下,它又一次只抓取了第一个提示者多次:s

谢谢

【问题讨论】:

    标签: python xpath scrapy


    【解决方案1】:

    当你说

    name = sel.xpath('td[@class="tipst"]/a/text()').extract()[0]
    

    XPath 表达式以td 开头,因此相对于变量sel 中的上下文节点(即tr 循环迭代的tr 元素集合中的tr 元素结束)。

    但是当你说

    name = sel.xpath('//td[@class="tipst"]/a/text()').extract()[0]
    

    XPath 表达式以//td 开头,即选择文档中任意位置的所有td 元素;这与sel 无关,因此在for 循环的每次迭代中,结果都是相同的。这就是为什么它一遍又一遍地刮掉第一个提示者。

    为什么第一个 XPath 表达式会因列表索引超出范围错误而失败?尝试一次使用 XPath 表达式,打印出结果,您很快就会发现问题所在。在这种情况下,这似乎是因为table[1] 的第一个tr 孩子没有td 孩子(只有th 孩子)。所以xpath() 什么都不选择,extract() 返回一个空列表,并且您尝试引用该空列表中的第一项,从而给出列表索引超出范围错误。

    要解决此问题,您可以将 for 循环 XPath 表达式更改为仅循环那些具有 td 子级的 tr 元素:

    for sel in response.xpath('//table[1]/tr[td]'):
    

    你可以变得更漂亮,需要一个正确类别的td

    for sel in response.xpath('//table[1]/tr[td[@class="tipst"]]'):
    

    【讨论】:

    • 感谢您的回复拉斯。自从尝试实现这一点以来,我在上面添加了一个编辑,但仍然没有运气!
    • @preach,即使我们更改了 for 循环语句的 XPath 表达式,sel 仍然包含 tr 元素,而不是 td 元素。这是因为 XPath 谓词(方括号中的内容)不指示进一步的定位步骤;他们只是过滤您已经选择的trs。因此,您需要将name 的XPath 更改为td[@class="tipst"]/a/text() 而不仅仅是a/text()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    相关资源
    最近更新 更多