type
status
date
slug
summary
tags
category
icon
password
comment
需求背景:部分站点比较久远,后台没有安装或部署自动更新.xml 脚本,于是只能想办法手动提交。网上有些可以生成的网站,但是要不然不能区分多语言,或者没法绕过验证。
第一步:先把架子搭起来
一个爬虫,最基本的就是三件事:发请求、解析页面、找链接。
- 发请求:我用的 requests 库,简单好用。
- 解析页面:BeautifulSoup 是老搭档了,从乱糟糟的 HTML 里提取东西很方便。
- 找链接:就是找所有的 <a> 标签。
为了不重复爬一个链接,我需要个东西记一下哪些网址已经爬过了。一开始用的是 Python 的 set。为了快一点,还得用多线程,所以我用了 ThreadPoolExecutor 来同时爬好几个页面。
这样,一个最基础的版本就有了。
第二步:网站太大,内存不够用了怎么办?
用 set 存爬过的网址,如果网站小还行。但遇到有几十万个页面的大网站,set 会占用非常多的内存,几个 G 都可能。
这时候我换了个东西,叫布隆过滤器 (Bloom Filter)。
你可以把它理解成一个“压缩版”的 set。它占内存非常小,但有个特点:它可能会把一个没爬过的网址,误报成“已经爬过了”(概率很低,可以自己设)。但它绝不会把爬过的,说成没爬过。
对于爬虫来说,偶尔漏掉一两个链接问题不大,但内存爆了程序就直接崩了。所以这个交换很划算。我用了 pybloom_live 这个库来实现。
第三步:对付 JS 动态加载的页面
现在很多网站,你用 requests 拿到的 HTML 是个空壳,内容都是靠浏览器里的 JavaScript 显示出来的。
对付这种网站,就得让我们的程序也模拟一个浏览器。我用的工具是 Selenium。
Selenium 可以控制一个真正的 Chrome 浏览器在后台运行,它能加载页面、执行 JS,我们最后再从它那里拿到渲染好的完整页面内容。
当然,网站也会检测你是不是个机器人。为了让我们的爬虫看起来更像一个真人在访问,我做了几件事:
- 换个身份:准备好几个常见的浏览器 User-Agent,每次请求都随机换一个。
- 动作慢一点:每次请求之间都随机停顿零点几秒,模拟人浏览网页的间隔。
- 做点伪装:通过一些设置,把 Selenium 自带的“我是自动化程序”的标记给去掉。
- 带上通行证:把登录或验证后网站给的 Cookie 保存下来,下次访问时带上,就不用重复验证了。
第四步:遇到最头疼的“验证码”
就算伪装得再好,访问多了,网站还是会弹出“拖动滑块完成验证”这种东西。
程序自己是很难拖对这个滑块的。所以我设计了一个比较“笨”,但很有效的办法:人机协作。
我的脚本里有个开关 MANUAL_VERIFICATION,打开后,如果程序检测到页面上出现了验证码(通过标题、内容关键字等判断):
- 它会自动弹出一个真实的浏览器窗口,把验证页面给你看。
- 电脑会“嘀”一声提醒你。
- 你有几十秒的时间,去手动把那个滑块给拖了。
- 等你验证通过,页面跳转了,程序会检测到,然后自动接管,继续闷头干活。
这个方法虽然不够“全自动”,但非常可靠。毕竟,人眼和人手是对付验证码最强的武器。
第五步:收工,整理成 Sitemap 文件
爬完所有链接后,最后一步就是把它们整理成标准的 sitemap.xml 格式。
这里我用 Python 自带的 xml 库来生成文件。我还加了个小功能,会根据网址的路径深度(比如 /a/b/c.html 深度是 3)来给它分配一个权重(priority),路径越浅的页面权重越高。
就是这么一步步,从一个简单的脚本,慢慢给它加上各种功能,最后变成一个能处理复杂网站的工具。整个过程就是不断发现问题、解决问题的循环。
完整代码:
- Author:Max
- URL:https://www.zhx1012.top//article/Simple-Sitemap-Generation-Code
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts