用 requests + BeautifulSoup 抓取 a 标签 href 更轻量,需过滤无效链接、用 urljoin 转绝对路径;并发控制在 3–5 线程、加随机延时与超时;去重后 UTF-8 编码保存;JS 渲染链接才用 Selenium/Playwright。

用 requests + BeautifulSoup 抓取页面内所有 a 标签的 href
直接发请求拿 HTML,比用 Selenium 轻量得多,只要目标网站没反爬或 JS 渲染依赖。注意别漏掉相对链接——urllib.parse.urljoin() 是必须的,否则提取出的 href="/about" 会变成无效本地路径。
常见错误:直接取 link.get("href") 就存,结果一堆 #top、javascript:void(0)、空字符串混进去。得过滤:
- 跳过
None或空字符串 - 排除以
#、javascript:、mailto:开头的值 - 用
urljoin(base_url, href)统一转成绝对 URL(base_url填你requests.get()的原始 URL)
批量处理多个 URL 时如何避免被封或超时
并发不是越多越好。requests 本身不支持异步,硬开 100 个线程容易触发连接拒绝或 IP 封禁。稳妥做法是控制并发数 + 加随机延时:
- 用
concurrent.futures.ThreadPoolExecutor(max_workers=3),别超过 5 - 每次请求前
time.sleep(random.uniform(1, 3)) - 必须设
timeout=(3, 7)(连接 3 秒,读取 7 秒),否则卡死进程 - 捕获
requests.exceptions.RequestException,跳过失败 URL,别让一个挂掉全盘崩
保存结果时为什么不能直接用 print() 或写文本文件
链接含特殊字符(比如中文、空格、& 符号)时,裸写文本会乱码或截断;更麻烦的是重复链接——同一页面可能有 5 个指向首页的 a,全存下来毫无意义。
实操建议:
- 用
set()去重,最后转list再写入 - 保存用
csv.writer或json.dump(),编码显式指定encoding="utf-8" - 别用
open(..., "w")直接覆盖,先写临时文件,校验无误再os.replace()
遇到 JavaScript 渲染的链接怎么办
requests 拿不到 document.write() 或 fetch() 动态插入的 a 标签。这时候才轮到 selenium 或 playwright 出场,但代价明显:
-
selenium启动浏览器慢,内存占用高,需额外装 ChromeDriver -
playwright更轻,但得用async写法,Python 3.10 支持没问题,但初学者容易卡在事件循环里 - 先确认是否真需要:查看网页源码(Ctrl+U),如果源码里本就没有链接,才是 JS 渲染;如果源码里有,只是前端又删了,那可能是逻辑过滤,不用上自动化浏览器
真正难的不是怎么取链接,而是判断哪些该取、哪些该丢——比如导航栏、页脚、广告位的链接,业务上往往要排除。这一步没法全自动,得靠人工规则或训练简单分类器,别指望一个正则包打天下。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











