跳到正文
写一个有礼貌的小爬虫:能抓和该抓是两件事
写一个有礼貌的小爬虫:能抓和该抓是两件事

写一个有礼貌的小爬虫:能抓和该抓是两件事

Python 阶段收尾写个小爬虫。这篇不讲 requests 和 BeautifulSoup 怎么用,讲我对「爬虫的水平不体现在抓得多猛,而在多有分寸」的判断——能抓不代表该抓。

速读#

这篇标题里有 requests 和 BeautifulSoup,但重点不是 HTML 怎么解析,而是“能抓”和“该抓”的边界。爬虫水平不体现在抓得多猛,而体现在频率、身份、timeout、robots.txt 这些分寸上;克制同时保护对方和自己。

水平在分寸,不在抓得猛#

把请求发得又多又快,技术上没有任何门槛——几行并发代码就能把频率推到对方明显吃不消的量级。真正难的是分寸感:对方的页面是对方花钱花算力供出来的资源,我的并发、频率、身份,是否在该用的范围内。

「能抓到更多」在技术上永远成立;「该不该抓到这个程度」是另一个问句。把两个问句分开,是这篇要立的判断。

我坚持的几条#

HEADERS = {"User-Agent": "s1oopx-learner/1.0"}
resp = requests.get(url, headers=HEADERS, timeout=10)
time.sleep(1) # 请求之间歇一下
该做的原因
看 robots.txt对方明确声明的不可抓区域要尊重
设置 timeout请求卡死别拖垮自己
请求间 sleep别把对方打爆,也降低被封风险
带 User-Agent表明身份,出问题对方能联系到你

timeout 和 sleep 既是对别人有分寸,也是对自己有保护——没 timeout 能挂死自己的程序,不 sleep 能封掉自己的 IP。克制在这件事上,和自利同向。

robots.txt 值得单独说一句:它不是墙,是声明。协议上没有任何强制力,绕过它一行代码都不用多写——正因为如此,遵不遵守才是个立场问题,不是技术问题。User-Agent 同理:写真实身份,而不是伪装成浏览器。哪天发现必须靠伪装才能继续抓,那一刻对方其实已经用技术手段说了「不欢迎」,再绕过去就是明知故犯。

失败是常态,不是意外#

写爬虫很快撞上一个事实:网络请求不是函数调用,失败是常态。超时、临时 5xx、被限流,都不该让程序裸崩。

resp = requests.get(url, headers=HEADERS, timeout=10)
resp.raise_for_status() # 4xx / 5xx 显式抛出来,别静默往下解析

不加这行,拿到一个 404 页面接着往下 BeautifulSoup,解析出一堆空值还不知道为什么——错误要在发生的那一层暴露,别让它伪装成数据问题漏到下一层。

失败之后怎么办也有分寸:临时错误可以重试,但要有上限,间隔要一次比一次拉开——指数退避是最省心的默认。无脑立刻重试等于把已经吃紧的对方打得更狠,恰好和「有礼貌」相反。重试用尽还拿不到,就先放弃、记下来,比死磕体面。

能抓 ≠ 该抓#

  • 公开 ≠ 允许:页面公开不代表授权你高频抓
  • 能复现登录态绕过 ≠ 该绕过:已越过「公开数据」边界

我没把「能抓到」当目标函数。这条线画在哪,取决于我愿不愿意把这套做法讲出来给对方看——讲不出口的,基本就不该做。

别把礼貌绝对化到不敢抓#

公开、允许抓取的数据,正常频率地抓,是合理使用。守的是分寸,不是停止。

后来用 Flask 调外部 API,基本就是这套排列组合:带 UA、带 timeout、控制频率。

有一次技术上几百 QPS 能跑,我仍选单线程加 2 秒 sleep——不急,没必要把别人服务器打爆。这个选择不是技术限制,是边界感。 后来延伸到运维:能开的端口不代表该开,能放的权不代表该放。

版权许可

CC BY-NC-SA 4.0 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

相关文章

s1oopX

登录 s1oopX