前言

如何优雅的获取同一个网站上下一次爬取的链接并放到生成一个 Scrapy Response 呢?

样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from urllib import parse

import scrapy


class SitoiSpider(scrapy.Spider):
name = "sitoi"

start_urls = [
'https://sitoi.cn',
]

def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/@href").extract()
for href in href_list:
url = parse.urljoin(response.url, href)
yield scrapy.Request(url=url, callback=self.parse_next)

def parse_next(self, response):
print(response.url)

方式一:使用 urllib 库来拼接 URL

这个方式是通过 urllib 库来对下一个 url 进行补全成完整的 url,再使用 scrapy.Request 的方式进行下一个页面的爬取。

优点

  1. 在处理每一个 href 的时候可以添加一些自定义的内容(例如记录一下当前第几页了等等)

缺点

  1. 需要引入其他的库
1
2
3
4
5
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/@href").extract()
for href in href_list:
url = parse.urljoin(response.url, href)
yield scrapy.Request(url=url, callback=self.parse_next)

方式二:使用 response 自带的 urljoin

这个方式是通过 Scrapy response 自带的 urljoin 对下一个 url 进行补全成完整的 url,再使用 scrapy.Request 的方式进行下一个页面的爬取。(和方式一基本相同)

优点

  1. 不再需要在 spider 文件中引入多的第三方库。
1
2
3
4
5
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/@href").extract()
for href in href_list:
url = response.urljoin(href)
yield scrapy.Request(url=url, callback=self.parse_next)

方式三:使用 response 自带的 follow

这个方式是通过 Scrapy response 自带的 follow 进行下一个页面的爬取。

优点

  1. 不再需要在 spider 文件中引入多的第三方库。
  2. 不需要写 extract() 来提取 href 字符串,只需要传入 href 这个 Selector(可选)
  3. 不需要写 url 拼接
  4. xpath 只需要编写到 a 标签即可,可以省略掉 @href,即不需要获取 href 的 Selector,直接传递 a 的 Selector(可选)
1
2
3
4
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/@href").extract()
for href in href_list:
yield response.follow(url=href, callback=self.parse_next)

变种一

  1. 不写 extract() 来提取 href 字符串,传入 href 这个 Selector
1
2
3
4
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/@href")
for href in href_list:
yield response.follow(url=href, callback=self.parse_next)

变种二

  1. 不写 extract() 来提取 href 字符串,传入 href 这个 Selector
  2. xpath 不写 @href,直接传递 a 的 Selector
1
2
3
4
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a/")
for href in href_list:
yield response.follow(url=href, callback=self.parse_next)

方式四:使用 response 自带的 follow_all

这个方式是通过 Scrapy response 自带的 follow_all 进行下一个页面的爬取。

优点

  1. 不再需要在 spider 文件中引入多的第三方库。
  2. 不需要写 extract() 来提取 href 字符串,只需要传入 href 这个 selector(可选)
  3. 不需要写 url 拼接
  4. 只需要编写到 a 标签即可,可以省略掉 @href,即不需要获取 href 的 SelectorList,直接传递 a 的 SelectorList(可选)
  5. 不需要编写遍历,直接把抓到的 url 的 SelectorList 放入即可

缺点

  1. 如果中间还有什么逻辑,就不太适用了(例如记录一下当前第几页了等等)
1
2
3
def parse(self, response):
href_list = response.xpath("//div[@class='card']/a")
yield from response.follow_all(urls=href_list, callback=self.parse_next)

变种

注:前方高能

一行代码搞定。

1
2
def parse(self, response):
yield from response.follow_all(xpath="//div[@class='card']/a", callback=self.parse_next)