我使用scrapy
在python中编写了一个脚本来解析网页中的一些信息。该网页中可用的数据遍历分页。如果我使用response.follow()
,那么我可以完成它。不过,我想按照requests
中BeautifulSoup
scrapy
中requests
实施的逻辑,但无法找到任何想法。
使用BeautifulSoup
和import requests
from bs4 import BeautifulSoup
page = 0
URL = 'http://esencjablog.pl/page/{}/'
while True:
page+=1
res = requests.get(URL.format(page))
soup = BeautifulSoup(res.text,'lxml')
items = soup.select('.post_more a.qbutton')
if len(items)<=1:break
for a in items:
print(a.get("href"))
我可以提出这样做,这很好:
scrapy
我想按照我上面应用的逻辑使用class PaginationTestSpider(scrapy.Spider):
name = 'pagination'
start_urls = ['http://esencjablog.pl/page/{}/'.format(page) for page in range(1,63)] #I used 63 here because the highest page number is 62
def parse(self, response):
for link in response.css('.post_more a.qbutton'):
yield{"link":link.css('::attr(href)').extract_first()}
做同样的事情,但每次我尝试执行它时,我最终会做如下的事情:
scrapy
再一次:我的问题是,如果我希望在requests
中使用BeautifulSoup
和{{1}}时最后页码未知的话,那么结构如何?是
答案 0 :(得分:3)
在这种情况下,您无法利用并行下载,但由于您希望在Scrapy中模拟相同的内容,因此可以通过不同的方式实现
方法1 - 使用页码的收益页面
class PaginationTestSpider(scrapy.Spider):
name = 'pagination'
# Start with page #1
start_urls = ['http://esencjablog.pl/page/1/']
def parse(self, response):
# we commnicate the page numbers using request meta
# this is not mandatory as we can extract the same data from
# the response.url also. But I prefer using meta here
page_no = response.meta.get('page', 1) + 1
items = response.css('.post_more a.qbutton')
for link in items:
yield{"link":link.css('::attr(href)').extract_first()}
if items:
# if items were found we move to the next page
yield Request("http://esencjablog.pl/page/{}".format(page_no), meta={"page": page_no}, callback=self.parse)
理想的方法通常是,如果您可以从第一个请求中找到最后一页的计数,那么您将提取该号码并在第一次parse
调用中将所有请求解压为一个。但这只有在可以知道最后页码
方法2 - 使用对象产生下一页
class PaginationTestSpider(scrapy.Spider):
name = 'pagination'
# Start with page #1
start_urls = ['http://esencjablog.pl/page/1/']
def parse(self, response):
items = response.css('.post_more a.qbutton')
for link in items:
yield{"link":link.css('::attr(href)').extract_first()}
next_page = response.xpath('//li[contains(@class, "next_last")]/a/@href')
if next_page:
yield response.follow(next_page) # follow to next page, and parse again
这只不过是@Konstantin所提到的一个直截了当的副本。对不起,但想让这个更完整的答案
方法3 - 在第一次回复时产生所有页面
class PaginationTestSpider(scrapy.Spider):
name = 'pagination'
# Start with page #1
start_urls = ['http://esencjablog.pl/page/1/']
first_request = True
def parse(self, response):
if self.first_request:
self.first_request = False
last_page_num = response.css("fa-angle-double-right::href").re_first("(\d+)/?$")
# yield all the pages on first request so we take advantage to parallel downloads
for page_no in range(2, last_page_num + 1):
yield Request("http://esencjablog.pl/page/{}".format(page_no), callback=self.parse)
items = response.css('.post_more a.qbutton')
for link in items:
yield {"link":link.css('::attr(href)').extract_first()}
此方法的最佳之处在于您浏览第一页,然后检查最后一页计数,并生成所有页面,以便同时进行下载。前两种方法本质上更顺序,如果你不想加载网站,你只会遵循它们。刮刀的理想方法是Approach 3
。
现在关于meta
对象的使用,在下面的链接
在此处添加相同内容以供参考
请求的回调是在下载该请求的响应时将被调用的函数。将使用下载的Response对象作为其第一个参数调用回调函数。
示例:
def parse_page1(self, response):
return scrapy.Request("http://www.example.com/some_page.html",
callback=self.parse_page2)
def parse_page2(self, response):
# this would log http://www.example.com/some_page.html
self.logger.info("Visited %s", response.url)
在某些情况下,您可能有兴趣将参数传递给那些回调函数,以便稍后在第二个回调中接收参数。您可以使用Request.meta属性。
以下是如何使用此机制传递项目以填充不同页面中的不同字段的示例:
def parse_page1(self, response):
item = MyItem()
item['main_url'] = response.url
request = scrapy.Request("http://www.example.com/some_page.html",
callback=self.parse_page2)
request.meta['item'] = item
yield request
def parse_page2(self, response):
item = response.meta['item']
item['other_url'] = response.url
yield item
答案 1 :(得分:0)
你必须使用scrapy.Request:
find /path/to/files -type f -mtime +30 -printf '%Ta %p\n' \
| grep -v ^Mon | cut -c5- | tr "\n" "\0" | xargs -0 rm -v
中找到更多详情
答案 2 :(得分:0)
您可以遍历这些页面scrapy doc:
class PaginationTestSpider(scrapy.Spider):
name = 'pagination'
start_urls = ['http://esencjablog.pl/page/1/'] # go to first page
def parse(self, response):
for link in response.css('.post_more a.qbutton'):
yield{"link":link.css('::attr(href)').extract_first()}
next_page = response.xpath('//li[contains(@class, "next_last")]/a/@href')
if next_page:
yield response.follow(next_page) # follow to next page, and parse again