【问题标题】:IndexError when using Scrapy for absolute links将 Scrapy 用于绝对链接时的 IndexError
【发布时间】:2016-09-28 10:27:11
【问题描述】:

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

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: 列表索引超出范围

谁能帮忙解释我哪里出错了?

【问题讨论】:

    标签: python json xpath scrapy


    【解决方案1】:

    因此,在将代码镜像到文档 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)
    

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

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

    标题,标题,标题,链接,链接,链接

    而不是

    标题、链接、标题、链接、标题、链接

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

    【讨论】:

      【解决方案2】:

      我认为你可以只连接两个字符串而不是使用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)
      

      【讨论】:

      • 是个好主意,但不幸的是出现了类型错误。 item["url"] = "http://en.wikipedia.org" + title.xpath("a/@href").extract() TypeError: cannot concatenate 'str' and 'list' objects
      • 有一个bug,需要做如下,item["url"] = "en.wikipedia.org" + title.xpath("a/@href").extract()[0 ]
      【解决方案3】:

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

      在新的迭代中,您使用了select 方法:url = title.select("a/@href").extract() 然后您将返回的对象视为可迭代对象,使用url[0]。检查select 方法返回什么,可能是一个列表,就像前面的例子一样。

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

      【讨论】:

      • 抱歉。那是我的错误。它应该是xpath 而不是selectselect 方法已弃用,将无法正常工作。
      【解决方案4】:

      为了更好的说明,我将修改上面的代码,

      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)
      

      【讨论】:

        猜你喜欢
        • 2012-04-02
        • 2010-10-07
        • 1970-01-01
        • 2015-01-13
        • 2011-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-04
        相关资源
        最近更新 更多