我使用Scrapy抓取网站,从各个页面提取数据,然后将抓取的数据存储到列表中。我试图从第一页抓取名称,网址和位置,然后从该抓取的网址遍历到该页面并从该页面刮掉DOCTYPE。请参阅下面的我制作的代码,我一直在密切关注 documentation ,但我得到了奇怪的结果。
如果我不尝试在我的ExampleSpider中使用第二种方法,我会返回3000+结果列表,这正是我想要的......减去必要的第二条数据。当我尝试包含此方法时,我所得到的只是起始网址(即。http://www.example.com,http://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
答案 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
。