我有一个形式的网址:
example.com/foo/bar/page_1.html
总共有53页,每页有~20行。
我基本上想要从所有页面获取所有行,即~53 * 20项。
我的解析方法中有工作代码,解析单个页面,每个项目的页面也更深一些,以获取有关该项目的更多信息:
def parse(self, response):
hxs = HtmlXPathSelector(response)
restaurants = hxs.select('//*[@id="contenido-resbus"]/table/tr[position()>1]')
for rest in restaurants:
item = DegustaItem()
item['name'] = rest.select('td[2]/a/b/text()').extract()[0]
# some items don't have category associated with them
try:
item['category'] = rest.select('td[3]/a/text()').extract()[0]
except:
item['category'] = ''
item['urbanization'] = rest.select('td[4]/a/text()').extract()[0]
# get profile url
rel_url = rest.select('td[2]/a/@href').extract()[0]
# join with base url since profile url is relative
base_url = get_base_url(response)
follow = urljoin_rfc(base_url,rel_url)
request = Request(follow, callback = parse_profile)
request.meta['item'] = item
return request
def parse_profile(self, response):
item = response.meta['item']
# item['address'] = figure out xpath
return item
问题是,如何抓取每个页面?
example.com/foo/bar/page_1.html
example.com/foo/bar/page_2.html
example.com/foo/bar/page_3.html
...
...
...
example.com/foo/bar/page_53.html
答案 0 :(得分:39)
您有两种方法可以解决您的问题。一般情况是使用yield
生成新请求而不是return
。这样,您可以从单个回调中发出多个新请求。检查http://doc.scrapy.org/en/latest/topics/spiders.html#basespider-example处的第二个示例。
在你的情况下,可能有一个更简单的解决方案:只需从这样的模式生成起始列表:
class MySpider(BaseSpider):
start_urls = ['http://example.com/foo/bar/page_%s.html' % page for page in xrange(1,54)]
答案 1 :(得分:11)
您可以使用CrawlSpider而不是BaseSpider,并使用SgmlLinkExtractor提取分页中的页面。
例如:
start_urls = ["www.example.com/page1"]
rules = ( Rule (SgmlLinkExtractor(restrict_xpaths=('//a[@class="next_page"]',))
, follow= True),
Rule (SgmlLinkExtractor(restrict_xpaths=('//div[@class="foto_imovel"]',))
, callback='parse_call')
)
第一条规则告诉scrapy遵循xpath表达式中包含的链接,第二条规则告诉scrapy将parse_call调用xpath表达式中包含的链接,以防你想要解析每个页面中的内容。
有关详细信息,请参阅文档:http://doc.scrapy.org/en/latest/topics/spiders.html#crawlspider
答案 2 :(得分:6)
'scrapy - 解析分页的项目可以有两个用例。
<强> A)。我们只想移动表并获取数据。这是相对简单的。
class TrainSpider(scrapy.Spider):
name = "trip"
start_urls = ['somewebsite']
def parse(self, response):
''' do something with this parser '''
next_page = response.xpath("//a[@class='next_page']/@href").extract_first()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
观察最后4行。这里
parse
回调方法的递归调用。 B)我们不仅希望跨页面移动,而且还希望从该页面中的一个或多个链接中提取数据。
class StationDetailSpider(CrawlSpider):
name = 'train'
start_urls = [someOtherWebsite]
rules = (
Rule(LinkExtractor(restrict_xpaths="//a[@class='next_page']"), follow=True),
Rule(LinkExtractor(allow=r"/trains/\d+$"), callback='parse_trains')
)
def parse_trains(self, response):
'''do your parsing here'''
在整个地方,观察:
我们正在使用CrawlSpider
父类的scrapy.Spider
子类
我们已设置为“规则”
a)第一条规则,只检查是否有“next_page”可用并跟随它。
b)第二条规则请求页面上所有格式的链接,例如/trains/12343
,然后调用parse_trains
执行和解析操作。
重要:请注意,由于我们使用parse
子类,因此我们不希望在此使用常规CrawlSpider
方法。这个类也有一个parse
方法,所以我们不想覆盖它。请记住将您的回拨方法命名为parse
以外的其他方法。