将Scrapy用于绝对链接时的IndexError

时间:2016-09-28 10:27:12

标签: python json xpath scrapy

我正在使用名为this的Python库从Wikipedia(特别是Scrapy)抓取一个网页。这是原始代码:

import scrapy
from wikipedia.items import WikipediaItem


class MySpider(scrapy.Spider):
    name = "wiki"
    allowed_domains = ["en.wikipedia.org/"]
    start_urls = [
        'https://en.wikipedia.org/wiki/Category:2013_films',
    ]

    def parse(self, response):
        titles = response.xpath('//div[@id="mw-pages"]//li')
        items = []
        for title in titles:
            item = WikipediaItem()
            item["title"] = title.xpath("a/text()").extract()
            item["url"] = title.xpath("a/@href").extract()
            items.append(item)
        return items

然后在终端中,我运行scrapy crawl wiki -o wiki.json -t json将数据输出到JSON文件。代码工作时,分配给" url"钥匙都是相关链接。 (即:{"url": ["/wiki/9_Full_Moons"], "title": ["9 Full Moons"]})。

我需要 http://en.wikipedia.org/wiki/9_Full_Moons ,而不是 / wiki / 9_Full_Moons 。所以我修改了上面提到的代码,从urlparse库中导入 urljoin 。我还修改了我的for循环,看起来像这样:

for title in titles:
    item = WikipediaItem()
    url = title.xpath("a/@href").extract()
    item["title"] = title.xpath("a/text()").extract()
    item["url"] = urljoin("http://en.wikipedia.org", url[0])
    items.append(item)
return(items)

我认为这是正确的方法,因为分配给url键的数据类型用括号括起来(这需要一个列表,对吧?)所以为了得到它里面的字符串,我键入了 URL [0] 即可。但是,这次我得到的IndexError如下所示:

  

IndexError:列表索引超出范围

有人可以帮我解释我哪里出错吗?

4 个答案:

答案 0 :(得分:0)

我认为您可以连接两个字符串而不是使用urljoin。试试这个:

for title in titles:
    item = WikipediaItem()
    item["title"] = title.xpath("a/text()").extract()
    item["url"] = "http://en.wikipedia.org" + title.xpath("a/@href").extract()[0]
    items.append(item)
return(items)

答案 1 :(得分:0)

在第一次使用相对链接的代码迭代中,您使用了xpath方法:item["url"] = title.xpath("a/@href").extract() 返回的对象是(我假设)一个字符串列表,因此索引它是有效的。

在新的迭代中,您使用了select方法:url = title.select("a/@href").extract()然后您将返回的对象视为可迭代的url[0]。检查select方法返回的内容,也许它是一个列表,如上例所示。

P.S。:IPython是你的朋友。

答案 2 :(得分:0)

因此,在将代码镜像到文档 here 中给出的示例之后,我能够让代码工作:

def parse(self, response):
    for text in response.xpath('//div[@id="mw-pages"]//li/a/text()').extract():
        yield WikipediaItem(title=text)
    for href in response.xpath('//div[@id="mw-pages"]//li/a/@href').extract():
        link = urljoin("http://en.wikipedia.org", href)
        yield WikipediaItem(url=link)

如果有人需要进一步澄清类的工作原理, the documentation is here

此外,尽管代码有效,但它不会将标题与其各自的链接配对。所以它会给你

  

TITLE,TITLE,TITLE,LINK,LINK,LINK

而不是

  

TITLE,LINK,TITLE,LINK,TITLE,LINK

(后者可能是更理想的结果) - 但这是另一个问题。如果有人提出的解决方案比我的解决方案更好,我会非常乐意听取你的答案!谢谢。

答案 3 :(得分:-1)

为了更好地澄清,我将修改上面的代码,

for title in titles:
    item = WikipediaItem()
    item["title"] = title.xpath("a/text()").extract()
    item["url"] = "http://en.wikipedia.org" + title.xpath("a/@href").extract()[0]
    items.append(item)
return(items)