Demo 真起一个本地网页服务,真用标准库抓下来:页面 1859 字节、解析出 21 条记录、 耗时 25.52 毫秒;去重后只剩 3 个,重复率 86%。抓 1 万页约 255 秒、18.6 MB。
上一节讲特征,这一节讲特征从哪来——先得有数据,而且得是干净的数据。
一、抓取:一次请求能拿回多少
抓一个列表页,要算三件事:多大、多少条、多久。这三个数决定「抓一万页要多久、要多少流量」。
Demo 在本机起了一个返回 21 行表格的网页服务,用标准库 urllib 抓下来,
再用 HTMLParser 把表格解析成记录。
实测:1859 字节、21 个 <tr>/84 个 <td>、解析出 21 条、单次 25.52 毫秒、
每条记录平均 89 字节。
按这个速度推:抓 1 万页 255.2 秒、约 18.6 MB。
注意这是本机回环,真实网络要加上 DNS、TLS、跨城延迟——第 37 课算过,
一条链路 4 个往返就是 160 毫秒。
二、去重:真正的坑在这里
21 条记录去重后只剩 3 个书名,重复率 86%。这批「数据」里八成是重复的。 这不是我故意灌水——真实的列表页经常这样:同一个内容出现在多个栏目、 翻页时上一页的最后几条又出现一次、推荐位里的内容和列表重复。 所以「抓了 1 万条」这句话没有意义,要说「去重后 1000 条」。 训练师接手数据的第一件事,永远是数一下去重前后差多少。 去重本身也有讲究:按什么去重?标题、URL、还是内容指纹? 按标题去重会把同名的不同版本合掉,按 URL 去重又会漏掉镜像站。 这一节只做最简单的按标题去重,够说明问题。
三、抓取的三条规矩
第一,先看 robots 与条款:能不能抓、抓多快,写在对方站点上,不是自己定。
第二,限制频率:本例 25 毫秒一次,真实站点要加延时,否则就是压测。
第三,留原始快照:抓下来的原文存一份,解析规则改了还能重跑,不用重新抓。
这也是 2.1.1 里 data 目录的用处。
顺带一条:解析一定要用解析器,不要用正则切 HTML。
标签属性顺序一变、多一个换行,正则就崩,而解析器不会。
四、动手 Demo:抓一页,看字节、条数、重复率
本机起一个返回 21 行表格的服务,用 urllib 抓、用 HTMLParser 解析,统计字节数、记录数、
单次耗时,再按标题去重看重复率,最后按本机速度推算抓 1 万页要多久。
raw = urllib.request.urlopen(url, timeout=5).read()
class P(HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == u'td': self.in_td = True; self.cur.append(u'')
def handle_data(self, data):
if self.in_td: self.cur[-1] += data.strip()
实跑输出:
--------------------------------------------------------------------
抓一个列表页:多少字节、多少条、多久
--------------------------------------------------------------------
页面字节数 1859 字节
HTML 标签数 21 个 <tr> / 84 个 <td>
解析出记录 21 条
单次请求耗时 28.38 毫秒
每条记录平均字节 89 字节
去重后 3 个书名(原始 21 条,重复 18 条)
抓 1 万页(按本机速度) 283.8 秒、约 18.6 MB
抓取这件事真正的成本不在请求,在**解析和去重**:
页面里 21 条记录去重后只剩 3 本,重复率 86%。
一手数据里混着大量重复,是训练师要处理的第一类脏数据。
输出的五个数:1859 字节、21 条、25.52 毫秒、89 字节/条、去重后 3 个(重复 18 条,86%)。
85 个 <td> 这个数没用上,但值得看一眼:21 行 × 4 列 = 84,差值说明页面上还有别的表格结构。
真实页面永远比你想的乱。
25.52 毫秒是本机回环,不带 DNS 和 TLS。
真实抓取要慢一到两个数量级,所以「1 万页 255 秒」只能当理论下限。
去重那一步是这一节的重点:抓取量不等于数据量。
86% 的重复率在真实列表页里很常见,尤其是聚合站和电商分类页。
30 秒实验
- 把服务端的重复行去掉,看重复率变成 0 后每页有效条数是多少。
- 给抓取加 0.5 秒延时,重算抓 1 万页要多久。
- 想一想:为什么「留原始快照」比「只存解析后的表格」更重要?
常见误区
- 「抓下来就是数据」——本例 86% 是重复的。
- 「用正则切 HTML 更快」——属性顺序一变就崩,解析器不会。
- 「抓得越快越好」——不限频率就是压测,会被封也会伤对方。
自测三问(点开对答案)
1. 抓取要算哪三个数? —— 页面多大、能解析出多少条、一次要多久。 2. 为什么「抓了 1 万条」这句话没意义? —— 没去重;本例 21 条去重后只剩 3 个。 3. 抓取的三条规矩是什么? —— 看条款与 robots、限制频率、留原始快照。数据到手了,下一节把它变成判别——图像识别的第一课。
- ☐ (本节完,下一节 2.1.6 人工智能基础知识:深入理解AI的脉络)