- 自动会话管理
- 锁定 195 个国家/地区的任意城市
- 无限并发会话
链接提取
简而言之:链接提取是爬虫从已抓取页面中提取 URL,以便将其加入队列并访问的步骤。爬虫在种子 URL 之外发现的所有内容都源于此步骤。
链接提取可以将单个页面的抓取转化为完整的爬取过程。获取页面后,爬虫工具会解析页面,识别其中包含的每个 URL,将这些 URL 解析为绝对形式,然后传递至 URL 待爬取队列。如果爬虫的链接提取能力不佳,无论其他配置优化得多么完善,都会漏掉网站中的大量内容。
链接所在的位置:
- 锚元素:锚标签上的
href属性包含了大多数可发现的链接。 - 链接元素:
link元素包含规范 URL、分页提示、其他语言版本和 Feed 地址。 - 框架和 iframe:
src属性指向嵌入式文档,而这些文档可能包含更多链接。 - 表单:
action属性会显示端点,但访问这些端点需要提交数据,而不是使用普通的 GET 请求。 - 站点地图:XML 站点地图可直接提供 URL 列表,无需解析页面标记。
- 嵌入式 JSON:API 响应以及 script 标签内的状态对象通常包含不会出现在可见标记中的 URL。
解析相对 URL:
真实 HTML 中的大多数链接都是相对 URL,必须先根据其所在页面进行解析,才能抓取。
| href 值 | 基于 https://example.com/shop/shoes/ 解析后的结果 |
|---|---|
| boots.html | https://example.com/shop/shoes/boots.html |
| /about | https://example.com/about |
| ../bags/ | https://example.com/shop/bags/ |
| //cdn.example.com/img.jpg | https://cdn.example.com/img.jpg |
| ?sort=price | https://example.com/shop/shoes/?sort=price |
如果存在 base 元素,它会覆盖页面 URL,作为解析基准。忽略该元素会生成看似合理、但在整个网站中都会返回 404 的 URL。
实际提取过程:
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def extract_links(html, page_url):
soup = BeautifulSoup(html, "lxml")
base_tag = soup.find("base", href=True)
base = urljoin(page_url, base_tag["href"]) if base_tag else page_url
links = set()
for tag in soup.find_all("a", href=True):
href = tag["href"].strip()
if href.startswith(("mailto:", "tel:", "javascript:", "#")):
continue
links.add(urljoin(base, href))
for tag in soup.find_all("link", href=True):
if tag.get("rel") and "next" in tag.get("rel"):
links.add(urljoin(base, tag["href"]))
return links
系统会丢弃非 HTTP 协议和纯片段链接,遵循 base 元素,并以集合形式返回结果,因此同一页面上的重复链接会立即合并。
解析器会漏掉的链接:
静态 HTML 解析只能看到服务器发送的内容。越来越多的链接只有在浏览器运行 JavaScript 后才会出现。
客户端路由。单页应用通常通过 JavaScript 路由器渲染导航,因此初始 HTML 中不会包含大多数路由的锚标签。
无限滚动。其他结果通过滚动触发的后台请求加载,绝不会出现在首次响应中。
点击处理程序。通过 onclick 处理程序而非 href 进行导航的元素,对查找锚链接的解析器而言是不可见的。
混淆链接。有些网站会特意通过 JavaScript 拼接 URL,以防静态解析器发现这些链接。
针对上述每种情况,解决方法都是先渲染页面再进行提取,这正是 JavaScript 渲染所提供的功能。Bright Data 的浏览器 API会在真实浏览器中执行页面,使渲染后的链接可供提取。
筛选提取的内容:
并非每个发现的链接都应加入队列。在 URL 进入待爬取队列前,提取流程通常会执行多项检查。
- 协议检查:丢弃所有不使用 HTTP 或 HTTPS 的链接。
- 范围检查:针对域名和路径边界应用爬取范围规则。
- 规范化:在进行任何比较前,先通过 URL 规范化将 URL 转换为规范形式。
- 去重:丢弃已经爬取或已加入队列的 URL。
- robots.txt 检查:确认此 User-Agent 可以访问该路径。
在提取阶段而非抓取阶段执行这些检查,可以缩小待爬取队列,并避免浪费带宽去发现某个 URL 根本就不该加入队列。
Nofollow 与爬虫行为:
rel="nofollow" 属性最初是作为提供给搜索引擎的信号,用于告知搜索引擎不要通过链接传递排名权重。它从来都不是爬取指令,并且搜索引擎在许多情况下仍会抓取 nofollow URL。
对于数据采集爬虫而言,没有义务遵循该属性,但它通常是一项有用的提示。标记为 nofollow 的链接往往来自用户生成内容、付费推广位或低价值分页,因此将它们设为较低优先级,而不是直接排除,通常能取得更好的平衡。