最近在做一些招聘市场的数据分析,碰到一个典型问题:分页数据抓不到头,还经常被限制请求。尤其像 51Job 这类网站,页面里几十条职位一页,你不翻页就只看到一角数据,翻太快又被挡。
后来我总结了一套思路,能稳定、低调地“翻完所有页”,还能直接把数据存进数据库做分析,效果还不错。想记录下来,一是备忘,二也分享给有同样需求的人。
我们日常在网上看到的很多数据,比如职位列表、评论、产品、新闻,它们都是分页呈现的。看着一页页翻,其实背后服务器也是靠 URL 参数拼接出来的数据。
我之前抓 51Job 的“Python爬虫”相关职位,每次第一页能抓,第二页开始就不是很稳定,甚至偶尔封我 IP。所以,不但要能翻页,还得稳 —— 这就是重点了。
我这次用的是 Python,主要是这些库:
requests
:发请求;beautifulsoup4
:解析网页;sqlite3
:写数据用的,内置,无需安装;pandas
:后面做点简单分析。另外我还加了一层代理 —— 用的是一个爬虫代理服务,不然抓多了很容易被“注意”。
咱先说下分页 URL 的套路。51Job 的搜索 URL 其实是类似这样的:
https://search.51job.com/list/000000,000000,0000,00,9,99,关键词,2,页码.html
这里的关键词可以换成 Python 爬虫
(需要转义一下),页码是从 1 开始递增的。
所以我做的就是:
import requests
import sqlite3
import time
import random
from bs4 import BeautifulSoup
import pandas as pd
from urllib.parse import quote
# 设置代理信息(用的是亿牛云)
proxy_host = "proxy.16yun.cn"
proxy_port = "3100"
proxy_user = "16YUN"
proxy_pass = "16IP"
# 拼接代理字典
proxies = {
"http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
"https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
}
# 随机浏览器头,尽量别被识别成脚本
headers = {
"User-Agent": random.choice([
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"Mozilla/5.0 (X11; Linux x86_64)"
])
}
# 搞个本地数据库来存
conn = sqlite3.connect("jobs_51job.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
company TEXT,
location TEXT,
salary TEXT,
date TEXT,
source_url TEXT
)
""")
conn.commit()
# 抓数据函数
def scrape_51job(keyword, max_pages=10):
print(f"开始抓取关键词:{keyword}")
for page in range(1, max_pages + 1):
try:
kw_encoded = quote(keyword)
url = f"https://search.51job.com/list/000000,000000,0000,00,9,99,{kw_encoded},2,{page}.html"
print(f"正在抓第 {page} 页:{url}")
res = requests.get(url, headers=headers, proxies=proxies, timeout=10)
res.encoding = 'gbk' # 指定编码,不然会乱码
soup = BeautifulSoup(res.text, "html.parser")
jobs = soup.select("div#resultList div.el")[1:] # 第一个是表头,跳过
for job in jobs:
title = job.select_one("p span a").get("title", "").strip()
company = job.select_one("span.t2 a").get("title", "").strip()
location = job.select_one("span.t3").text.strip()
salary = job.select_one("span.t4").text.strip()
date = job.select_one("span.t5").text.strip()
link = job.select_one("p span a").get("href", "").strip()
cursor.execute("""
INSERT INTO jobs (title, company, location, salary, date, source_url)
VALUES (?, ?, ?, ?, ?, ?)
""", (title, company, location, salary, date, link))
conn.commit()
print(f"第 {page} 页 OK,共抓了 {len(jobs)} 条")
time.sleep(random.uniform(1, 3)) # 随机等一下,低调点
except Exception as e:
print(f"第 {page} 页挂了:{e}")
continue
# 数据分析函数:看看哪月招聘多
def analyze_jobs():
df = pd.read_sql_query("SELECT * FROM jobs", conn)
df["month"] = df["date"].apply(lambda x: "2025-" + x[:2] if "-" in x else "未知")
stats = df.groupby("month").size().reset_index(name="job_count")
stats = stats.sort_values(by="month")
print("\n【每月职位数统计】")
for _, row in stats.iterrows():
print(f"{row['month']} 月份发布职位数量:{row['job_count']} 条")
# 主流程
if __name__ == "__main__":
scrape_51job("Python 爬虫", max_pages=5)
analyze_jobs()
conn.close()
我抓的过程中,也踩了些坑,这里说下:
res.encoding = 'gbk'
,中文就全花了。像这种分页抓数据的逻辑,其实大部分网站都差不多,你只要搞清楚分页 URL 的规律,再加上低调的抓法,就可以抓得很稳定。
我这次把数据存进 SQLite,是为了后面能做分析,比如看哪月招聘多,哪类岗位常见等。后续可以考虑导出 CSV、入库 MySQL、甚至做成一个可视化看板。
希望这篇小记对你有帮助。如果你也在爬分页,不妨试试看这种“翻书式”的思路!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。