很多网站为了获取 pv, 会把一篇完整的文章分成多页, 这也给爬虫抓取造成了一些小问题。
分页文章
常规的做法是先解析第一页数据,保存到 item , 再检测是否存在下一页, 如果存在,重复执行抓取函数, 直到到最后一页停止。
但是在scrapy 中有一个问题, scrapy 中的回调函数无法返回值,抓取的文章正文无法返回, 所以这里可以用 request 的 meta 属性单向传递item变量到抓取函数中。
def parse_article(self, response):
"""parse article content
Arguments:
response {[type]} -- [description]
"""
selector = Selector(response)
article = ArticleItem()
# 先获取第一页的文章正文
article['content'] = selector.xpath(
'//article[@class="article-content"]').get()
# 拆分最后一页的 url, 可以得到文章的base url 和总页数
page_end_url = selector.xpath(
'//div[@class="pagination"]/ul/li/a/@href').extract()[-1]
page_base_url, page_count = re.findall(
'(.*?)_(.*?).html', page_end_url)[0]
page_count = int(page_count)
for page in range(2, page_count + 1):
# 构造出分页 url
url = page_base_url + '_{}.html'.format(page)
# 手动生成 Request 请求, 注意函数中的 priority 参数, 代表了 Request 是按顺序执行的, 值越大, 优先级越高
request = Request(url=url, callback=self.parse_content, priority=-page)
# 向 self.parse_content 函数传递 item 变量
request.meta['article'] = article
yield request
self.parse_content
中主要是抓取文章正文, 并存入 item 的操作
def parse_content(self, response):
selector = Selector(response)
article = response.meta['article']
# 注意这里对 article['content']的操作是 +=, 这样不会清空上一页保存的数据
article['content'] += selector.xpath('//article[@class="article-content"]').get()
yield article
Reference: Requests and Responses
网友评论