Scrapy - 从多个页面解析数据

时间:2014-12-30 19:06:25

标签: python regex xpath scrapy

我使用Scrapy抓取网站,从各个页面提取数据,然后将抓取的数据存储到列表中。我试图从第一页抓取名称,网址和位置,然后从该抓取的网址遍历到该页面并从该页面刮掉DOCTYPE。请参阅下面的我制作的代码,我一直在密切关注 documentation ,但我得到了奇怪的结果。

如果我不尝试在我的ExampleSpider中使用第二种方法,我会返回3000+结果列表,这正是我想要的......减去必要的第二条数据。当我尝试包含此方法时,我所得到的只是起始网址(即。http://www.example.comhttp://www.example1.com等)。

有关我在这里做错了什么的建议吗?

import scrapy
from scrapy.contrib.loader import ItemLoader
from example.items import Item
from scrapy.http import Request
import re

class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]
    start_urls = ["list of about 15 different websites (ie. 'http://example.com', 'http://example1.com')"]

    # #Working method to scrape all of the data I need (except DOCTYPE from second page)
    # def parse(self, response):
    #   for sel in response.xpath('//table[@class="rightLinks"]/tr'):
    #     item = Item()
    #     item['company_name'] = sel.xpath('td[1]/a/text()').extract()
    #     item['website'] = sel.xpath('td[1]/a/@href').extract()
    #     item['location'] = sel.xpath('td[2]/text()').extract()
    #     yield item


    def parse(self, response):
      for sel in response.xpath('//table[@class="rightLinks"]/tr'):
        item = PharmaItem()
        item['company_name'] = sel.xpath('td[1]/a/text()').extract()
        item['website'] = sel.xpath('td[1]/a/@href').extract()
        item['location'] = sel.xpath('td[2]/text()').extract()
        #Setting up a new request to pass to the get_DT method, also passing along the 'item' class meta data

        #converting website from list item to string
        website = ''.join(item['website'])
        request = scrapy.Request(website, callback=self.get_DT)
        request.meta['item'] = item

        return request

    #Get DOCTYPE from each page
    def get_DT(self, response):
        item = response.meta['item']
        item['website'] = response.url
        dtype  = re.search("<!\s*doctype\s*(.*?)>", response.body, re.IGNORECASE)
        item['DOCTYPE'] = dtype

        yield item

UPDATE 这是我使用过的两个最终功能。我取消了白痴的建议并尝试了但是这并没有奏效,因为它不断返回父DOCTYPE而不是遍历的页面DOCTYPE。

  def parse(self, response):
    for sel in response.xpath('//table[@class="rightLinks"]/tr'):
      item = PharmaItem()
      item['company_name'] = sel.xpath('td[1]/a/text()').extract()
      website = sel.xpath('td[1]/a/@href').extract()[0]
      item['location'] = sel.xpath('td[2]/text()').extract()

      # Setting up a new request to pass to the get_DT method, also passing along the 'item' class meta data
      request = scrapy.Request(website, callback=self.get_DT)
      request.meta['item'] = item
      yield request

  #Takes in the websites that were crawled from previous method and finds DOCTYPES
  def get_DT(self, response):
    item = response.meta['item']
    item['DOCTYPE'] = response.selector._root.getroottree().docinfo.doctype
    item['website'] = response.url

    yield item

2 个答案:

答案 0 :(得分:1)

您正在运行循环,但在其中调用return。它将阻止循环通过所有链接。请改用yield函数中的parse()

除此之外,我没有得到这一部分:

#converting website from list item to string
website = ''.join(item['website'])

这似乎不对。如果那里有多个网址,则会导致网址非常糟糕且无效。如果只有其中一个,那么你应该通过获取第一个也是唯一的列表元素来收集它(注意最后的[0]):

item['website'] = sel.xpath('td[1]/a/@href').extract()[0]

此外,我不确定您为什么要在item['website']函数中设置parse(),因为无论如何您都要在get_DT函数中覆盖它。你应该只使用一个临时变量,如下所示:

for sel in response.xpath('//table[@class="rightLinks"]/tr'):
    item = PharmaItem()
    item['company_name'] = sel.xpath('td[1]/a/text()').extract()
    item['location'] = sel.xpath('td[2]/text()').extract()
    website = sel.xpath('td[1]/a/@href').extract()
    request = scrapy.Request(website, callback=self.get_DT)
    request.meta['item'] = item
    yield request

答案 1 :(得分:1)

我同意劳伦斯关于解决这条问题。

另外,我不确定为什么你有这个回调函数。您可以通过以下方式轻松获取doctype:

import requests
html = requests.get('http://something.com').content
dtype = re.search("<!\s*doctype\s*(.*?)>", html, re.IGNORECASE)

我从未使用scrapy.Requests,所以我在这里使用了很好的requests