2.5 Link Extractors (链接提取器) 2.5 Link Extractors (链接提取器) 在 Scrapy 爬虫中,链接提取器 (Link Extractors) 扮演着至关重要的角色。它们负责从 HTML 或 XML 文档中提取链接,以便爬虫能够沿着这些链接继续抓取其他页面。如果没有链接提取器,爬虫就只能抓取起始页面,而无法深入到网站的其他部分。 2.5.1 链接提取器的作用 链接提取器的主要作用是: 发现新的 URL: 从已抓取的页面中找到新的 URL,这些 URL 指向网站的其他页面或外部资源。 控制爬取范围: 通过设置规则,可以限制爬虫只抓取特定类型的链接,例如只抓取属于特定域名的链接或符合特定模式的链接。
在 Scrapy 爬虫中,链接提取器 (Link Extractors) 扮演着至关重要的角色。它们负责从 HTML 或 XML 文档中提取链接,以便爬虫能够沿着这些链接继续抓取其他页面。如果没有链接提取器,爬虫就只能抓取起始页面,而无法深入到网站的其他部分。
链接提取器的主要作用是:
发现新的 URL: 从已抓取的页面中找到新的 URL,这些 URL 指向网站的其他页面或外部资源。
控制爬取范围: 通过设置规则,可以限制爬虫只抓取特定类型的链接,例如只抓取属于特定域名的链接或符合特定模式的链接。
简化爬虫代码: 将链接提取的逻辑从爬虫代码中分离出来,使爬虫代码更加简洁和易于维护。
Scrapy 提供了 scrapy.linkextractors 模块,其中包含了一些常用的链接提取器。最常用的链接提取器是 LxmlLinkExtractor,它基于 lxml 库,具有高性能和灵活性。
from scrapy.linkextractors import LxmlLinkExtractor
LxmlLinkExtractor 的常用参数LxmlLinkExtractor 提供了丰富的参数,可以根据不同的需求进行配置。以下是一些常用的参数:
allow (str or iterable): 一个正则表达式或一个正则表达式列表,用于匹配允许提取的 URL。只有匹配该正则表达式的 URL 才会被提取。
deny (str or iterable): 一个正则表达式或一个正则表达式列表,用于匹配禁止提取的 URL。匹配该正则表达式的 URL 将不会被提取。
allow_domains (str or iterable): 一个域名或一个域名列表,用于指定允许提取链接的域名。
deny_domains (str or iterable): 一个域名或一个域名列表,用于指定禁止提取链接的域名。
restrict_xpaths (str or iterable): 一个 XPath 表达式或一个 XPath 表达式列表,用于指定在哪些 XPath 区域内提取链接。
restrict_css (str or iterable): 一个 CSS 选择器或一个 CSS 选择器列表,用于指定在哪些 CSS 选择器区域内提取链接。
tags (str or iterable): 一个标签名或一个标签名列表,用于指定要提取链接的标签。默认为 ('a', 'area')。
attrs (str or iterable): 一个属性名或一个属性名列表,用于指定要提取链接的属性。默认为 ('href',)。
canonicalize (bool): 是否对提取的 URL 进行规范化处理。默认为 True。
下面通过一个简单的例子来演示如何使用 LxmlLinkExtractor。
示例:提取博客文章列表页面的文章链接
假设我们要从一个博客的文章列表页面提取所有文章的链接。该页面的 HTML 结构如下:
<div class="article-list"> <article> <h2><a href="/article/1">文章1</a></h2> <p>文章1的摘要...</p> </article> <article> <h2><a href="/article/2">文章2</a></h2> <p>文章2的摘要...</p> </article> <article> <h2><a href="/article/3">文章3</a></h2> <p>文章3的摘要...</p> </article> </div>
我们可以使用以下代码来提取文章链接:
import scrapy from scrapy.linkextractors import LxmlLinkExtractor class BlogSpider(scrapy.Spider): name = "blog_spider" start_urls = ["http://example.com/blog"] # 替换成你的博客列表页URL def parse(self, response): # 创建一个 LxmlLinkExtractor 实例,restrict_xpaths 指定提取链接的区域 le = LxmlLinkExtractor(restrict_xpaths="//div[@class='article-list']/article/h2") # 使用 extract_links 方法提取链接 links = le.extract_links(response) # 遍历提取到的链接 for link in links: print(f"提取到的链接:{link.url}") # 可以对提取到的链接进行进一步处理,例如发起新的请求 # yield scrapy.Request(link.url, callback=self.parse_article) def parse_article(self, response): # 这里编写解析文章页面的代码 pass
代码解释:
导入模块: 导入 scrapy 和 LxmlLinkExtractor。
定义 Spider 类: 创建一个名为 BlogSpider 的 Spider 类,并设置 name 和 start_urls。
parse 方法: 这是爬虫的主要解析方法。
创建 LxmlLinkExtractor 实例,并使用 restrict_xpaths 参数指定只在 class="article-list" 的 div 元素下的 article 元素下的 h2 元素中提取链接。
调用 extract_links 方法,传入 response 对象,该方法会返回一个 Link 对象列表。
遍历 Link 对象列表,打印提取到的 URL。
(可选) 可以使用 yield scrapy.Request 发起新的请求,抓取文章页面。
parse_article 方法: (可选) 用于解析文章页面的方法。
运行爬虫:
将以上代码保存为 blog_spider.py,然后在命令行中运行以下命令:
scrapy crawl blog_spider
爬虫将会抓取 start_urls 中指定的页面,并提取所有符合条件的链接,并在控制台中打印出来。
allow 和 deny 参数allow 和 deny 参数可以用来更精确地控制链接提取。
示例:只提取包含 "article" 的链接,排除包含 "category" 的链接
import scrapy from scrapy.linkextractors import LxmlLinkExtractor class BlogSpider(scrapy.Spider): name = "blog_spider" start_urls = ["http://example.com/blog"] # 替换成你的博客列表页URL def parse(self, response): # 创建一个 LxmlLinkExtractor 实例,使用 allow 和 deny 参数 le = LxmlLinkExtractor(allow="article", deny="category") # 使用 extract_links 方法提取链接 links = le.extract_links(response) # 遍历提取到的链接 for link in links: print(f"提取到的链接:{link.url}") # 可以对提取到的链接进行进一步处理,例如发起新的请求 # yield scrapy.Request(link.url, callback=self.parse_article) def parse_article(self, response): # 这里编写解析文章页面的代码 pass
在这个例子中,allow="article" 表示只提取 URL 中包含 "article" 的链接,deny="category" 表示排除 URL 中包含 "category" 的链接。
restrict_css 参数restrict_css 参数可以使用 CSS 选择器来指定提取链接的区域。
示例:提取 class="article-list" 的 div 元素下的所有链接
import scrapy from scrapy.linkextractors import LxmlLinkExtractor class BlogSpider(scrapy.Spider): name = "blog_spider" start_urls = ["http://example.com/blog"] # 替换成你的博客列表页URL def parse(self, response): # 创建一个 LxmlLinkExtractor 实例,使用 restrict_css 参数 le = LxmlLinkExtractor(restrict_css=".article-list") # 使用 extract_links 方法提取链接 links = le.extract_links(response) # 遍历提取到的链接 for link in links: print(f"提取到的链接:{link.url}") # 可以对提取到的链接进行进一步处理,例如发起新的请求 # yield scrapy.Request(link.url, callback=self.parse_article) def parse_article(self, response): # 这里编写解析文章页面的代码 pass
在这个例子中,restrict_css=".article-list" 表示只在 class="article-list" 的 div 元素下提取链接。
虽然 Scrapy 提供了默认的链接提取器,但在某些情况下,可能需要自定义链接提取器来满足特定的需求。 可以继承 scrapy.linkextractors.LinkExtractor 类并重写其方法来实现自定义的链接提取逻辑。
from scrapy.linkextractors import LinkExtractor from scrapy.link import Link class MyLinkExtractor(LinkExtractor): def __init__(self, *args, **kwargs): super(MyLinkExtractor, self).__init__(*args, **kwargs) def extract_links(self, response): # 自定义链接提取逻辑 links = [] # ... (你的提取逻辑) ... return links
图示解释:
爬虫接收到 Response 对象。
Response 对象被传递给 LxmlLinkExtractor 实例。
LxmlLinkExtractor 根据配置的规则 (例如 allow、deny、restrict_xpaths 等) 从 Response 中提取链接。
符合规则的链接被封装成 Link 对象。
不符合规则的链接被忽略。
LxmlLinkExtractor 返回一个 Link 对象列表。
链接提取器是 Scrapy 爬虫中不可或缺的组件。通过灵活配置链接提取器的参数,可以精确控制爬虫的抓取范围,提高爬虫的效率。 掌握链接提取器的使用方法,可以让你编写出更加强大和高效的 Scrapy 爬虫。