Scrapy 的工作原理
Scrapy 项目会定义一个或多个 Spider。每个 Spider 都会生成请求,在回调方法中处理响应,并使用 CSS 选择器或 XPath 提取字段。Spider 还可以跟踪符合条件的链接,从而充当网络爬虫。
Scrapy 能并发调度和下载大量页面,无需为每个页面启动浏览器。提取的数据项可经过 Pipeline,由其验证值、删除重复项,并将结果写入 JSON、CSV 或数据库。
通过代理发送 Scrapy 请求
Scrapy 内置的代理中间件会读取每个请求元数据中的 proxy 值。以下示例通过需要认证的代理发送请求,并提取页面标题:
import scrapy
class ProductSpider(scrapy.Spider):
name = "products"
def start_requests(self):
yield scrapy.Request(
"https://example.com/products",
meta={"proxy": "http://USERNAME:PASSWORD@HOST:PORT"},
)
def parse(self, response):
yield {"title": response.css("title::text").get()}
在生产环境中,应将认证凭据放在源代码之外。使用代理池时,中间件可为每个相互独立的请求选择不同的代理。如果多个请求属于同一会话,应保持使用相同的代理和 Cookie。代理可以更改源 IP,但无法修正不合常理的请求头或过高的请求频率。
Scrapy、Beautiful Soup 与 Selenium 对比
这些工具分别用于解决数据采集中的不同环节。
| 工具 | 是否运行浏览器 | 最适合的场景 |
|---|---|---|
| Scrapy | 否 | 采集大量 HTML 或 JSON 页面 |
| Beautiful Soup | 否 | 解析已经获取的 HTML |
| Selenium | 是 | 浏览器交互和需要 JavaScript 渲染的页面 |
Beautiful Soup 可以在 Scrapy 中使用,不过 Scrapy 的选择器通常也能完成相同的解析任务。Selenium 需要控制浏览器,因此占用的内存更多,但可以处理需要点击或执行 JavaScript 的页面。
局限与采集规范
Scrapy 默认不执行页面中的 JavaScript。如果数据稍后才会加载,应检查网站的公开 API;如果网站条款允许自动化操作,也可以集成浏览器工具。
使用 CONCURRENT_REQUESTS_PER_DOMAIN、DOWNLOAD_DELAY 和 AUTOTHROTTLE_ENABLED 控制负载。如果网站返回 429 Too Many Requests,应降低请求频率,而不是轮换 IP 后立即重试。请遵守 robots.txt、访问控制规则和网站条款。
常见问题
Scrapy 比 Beautiful Soup 更好吗?
视情况而定。Scrapy 更适合完整的采集项目;如果只需解析其他工具已获取的 HTML,Beautiful Soup 更简单。
Scrapy 能采集 JavaScript 网站吗?
Scrapy 本身不能。它会下载 HTTP 响应,但不会执行 JavaScript,因此动态页面可能需要使用提供数据的 JSON 端点或浏览器自动化工具。
Scrapy 支持需要认证的代理吗?
支持。在请求的 proxy 元数据中填入 http://USERNAME:PASSWORD@HOST:PORT。如果请求未携带有效的代理认证凭据,代理服务器会返回 407 Proxy Authentication Required。