您现在的位置是:烟消火灭网 > 知识

爬虫一个网站

烟消火灭网2026-10-17 07:48:25【知识】0人已围观

简介写爬虫的人都有个习惯:打开一个网站,先按 F12。这不是什么技术信仰,就是手痒。我盯着某个招聘网站看了三天,发现它的岗位列表页 URL 长这样:/jobs?city=beijing&page=1。翻到

写爬虫的爬虫人都有个习惯:打开一个网站,先按 F12。个网这不是爬虫什么技术信仰,就是个网手痒。我盯着某个招聘网站看了三天,爬虫发现它的个网岗位列表页 URL 长这样:/jobs?city=beijing&page=1。翻到第二页,爬虫page 变成 2,个网其他参数纹丝不动。爬虫这就等于把门钥匙挂在锁上。个网

我决定拿它练手。爬虫目标很简单——把北京地区所有"Python"关键词的个网岗位标题、公司名、爬虫薪资范围抓下来,个网存成一个 CSV。爬虫听起来像是个周末下午就能搞定的活儿,但真正动手才知道,每个网站都有自己的脾气。

先看它怎么跟服务器说话

打开开发者工具的 Network 面板,刷新页面。一堆请求里,找到那个返回 HTML 的文档请求。右键,Copy as cURL。粘贴到终端里跑一遍,确认能拿到同样的内容。这一步很重要,很多教程跳过它直接上 requests,结果被反爬拦了还不知道问题出在哪。

我用的 Python,requests + BeautifulSoup 组合。先写个最小可运行版本:

import requests from bs4 import BeautifulSoup url = "https://example.com/jobs?city=beijing&page=1" headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."} resp = requests.get(url, headers=headers) soup = BeautifulSoup(resp.text, "html.parser") jobs = soup.select(".job-item") print(len(jobs)) 

跑出来 15 条。跟页面上显示的数量对上了。这时候心里踏实了一半。

翻页这件事,比想象中麻烦

第一页顺利,不代表第十页也顺利。我写了个循环,page 从 1 到 50。跑到第 7 页的时候,返回的 HTML 里 .job-item 数量变成 0。打开浏览器手动翻到第 7 页——正常显示。问题出在请求头。那个网站对连续快速请求有频率限制,超过阈值就返回一个空壳页面,HTTP 状态码还是 200。这种"软封禁"最恶心,你以为是选择器写错了,其实是服务器在敷衍你。

解决办法笨但有效:每请求一页,time.sleep(random.uniform(1.5, 3.5))。随机间隔比固定间隔更难被识别。另外把 Referer 头补上,让请求看起来像是从站内跳转过来的。

数据清洗才是真正花时间的地方

抓下来的薪资字段长这样:"15-25K·13薪"、"20-40K"、"面议"。想存成结构化数据,得写正则拆。我一开始用 split("-"),碰到"面议"直接报错。后来改成先判断是否包含"K",再提取数字。这种脏活没有捷径,只能一条条看数据长什么样,然后写对应的处理逻辑。

公司名里混着全角和半角括号,标题里有 HTML 实体字符  。BeautifulSoup 的 get_text() 能解决大部分,但总有几个漏网的。我最后加了一步 html.unescape(),世界清净了。

别忽略 robots.txt

抓之前我看了眼 /robots.txt。Disallow 里列了 /admin/ 和 /api/,岗位列表页不在禁止范围内。这算运气好。有些网站直接 Disallow: /,那就别硬来了。技术上行得通不代表应该做。我给自己定的规矩是:只抓公开列表页,不碰用户数据,请求频率控制在人手动翻页的水平。

最后跑完 50 页,拿到 600 多条记录。CSV 打开一看,有几条重复的——网站本身在不同页码里放了相同的岗位。去重逻辑加在 pandas 里,一行 drop_duplicates(subset="job_id") 搞定。整个脚本不到 80 行,写加调试花了四个小时。其中三个半小时在跟反爬机制和数据清洗较劲,真正写爬取逻辑的时间不到半小时。

这就是爬虫的真相:代码本身不复杂,复杂的是理解目标网站的行为模式,以及接受它随时可能改变的事实。下周那个网站改版了,选择器全变,我又得重新来一遍。但至少这次,我知道该从 F12 开始。

很赞哦!(7)