第二次作业:数据采集与融合技术
第二次作业:数据采集与融合技术实战(102402114)
学号: 102402114
姓名: 谢慧彬
Gitee 仓库链接: 【此处填入你的 Gitee 仓库地址】
本次作业共包含三个任务:① 中国气象网 7 日天气预报爬取;② 东方财富网股票信息爬取;③ 软科 2021 中国大学排名爬取。三个任务均使用 Python 编写,数据统一存储在 SQLite 数据库中。
爬虫代码实现与运行结果展示
作业①——中国气象网 7 日天气预报爬取
(1)F12 调试分析过程
为了获取天气数据,首先在浏览器中打开中国天气网北京页面( http://www.weather.com.cn/weather/101010100.shtml ),并按 F12 打开开发者工具:
- 在 Network(网络) 面板中选择
Doc过滤标签,刷新网页后找到主文档请求101010100.shtml。

- 点击该请求,切换到 Response(响应) 面板,即可看到网页返回的 HTML 源码。

- 在源码中搜索
7日,成功定位到包含 7 天天气数据的<ul class="t clearfix">列表,其下每个<li>标签对应一天。

- 可以清晰看到数据直接写在 HTML 结构中:日期在
<h1>标签、天气在<p class="wea">、温度在<p class="tem">里。
结论:天气数据是静态渲染的,直接使用 requests 请求网页 + BeautifulSoup 解析 HTML 即可,无需模拟浏览器。
(2)核心代码
import requests
from bs4 import BeautifulSoup
def crawl_weather(city_name, city_code):
"""定向爬取指定城市(city_code)的 7 天天气预报"""
url = f"http://www.weather.com.cn/weather/{city_code}.shtml"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"}
response = requests.get(url, headers=headers)
response.encoding = "utf-8" # 防止中文乱码
soup = BeautifulSoup(response.text, "html.parser")
ul = soup.find("ul", class_="t clearfix") # 7 天数据所在列表
lis = ul.find_all("li") if ul else []
weather_data = []
for li in lis:
date = li.find("h1").text.strip() # 日期
weather = li.find("p", class_="wea").text.strip() # 天气
tem_p = li.find("p", class_="tem")
temp_high = tem_p.find("span").text.strip() # 最高温
temp_low = tem_p.find("i").text.strip() # 最低温
weather_data.append((city_name, date, weather,
temp_high.replace("℃", ""),
temp_low.replace("℃", "")))
return weather_data
# 之后用 sqlite3 建表(UNIQUE(city, date) 约束)并 INSERT OR REPLACE 写入,代码略
(3)运行结果


运行后共入库 21 条数据(3 个城市 × 7 天),存储在 weather.db 的 weather_7days 表中。
作业②——东方财富网股票信息爬取
(1)F12 调试分析过程
在爬取东方财富网股票数据时,最初在 Network 面板抓包并未直接找到目标数据。经过把过滤条件切换为 Fetch/XHR 并多次刷新页面后,成功抓到了名为 get?pn=1&pz=20... 的 API 请求。
分析该请求发现:
- 请求地址为
https://push2.eastmoney.com/api/qt/clist/get,返回的是标准 JSON 数据。

- URL 中有多个 Query 参数:
pn(页码)、pz(每页数量)、fields(请求字段)、fid(排序字段)等。

- 返回 JSON 中的字段含义:
f12=股票代码、f14=股票名称、f2=最新价、f3=涨跌幅、f5=成交量、f6=成交额。
结论:股票数据由前端通过 Ajax 向后端 API 请求而来,直接构造请求参数调用该 API,再用 requests + json 解析即可,无需渲染整页。
(2)核心代码
import requests
import json
def crawl_stock(page):
"""请求东方财富 API 并解析 JSON 数据(page 为页码)"""
url = "https://push2.eastmoney.com/api/qt/clist/get"
params = { # 根据 F12 抓包分析构造的参数
"pn": str(page), # 页码
"pz": "100", # 每页数量
"fid": "f3", # 按涨跌幅排序
"fs": "m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048", # 沪深A股
"fields": "f2,f3,f5,f6,f12,f14" # 价格/涨跌幅/成交量/成交额/代码/名称
}
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"}
response = requests.get(url, params=params, headers=headers, timeout=10)
text = response.text
# 兼容 JSONP 格式(形如 callback({...}))
if text.startswith("{"):
data = json.loads(text)
else:
data = json.loads(text[text.find("(") + 1:text.rfind(")")])
# data["data"]["diff"] 即股票列表:f12=代码 f14=名称 f2=最新价 f3=涨跌幅 f5=成交量 f6=成交额
return data["data"]["diff"]
# 之后将每只股票的 f12/f14/f2/f3/f5/f6 写入 sqlite3(stock_data 表),代码略
(3)运行结果


运行后共入库 298 条股票数据,存储在 stock.db 的 stock_data 表中,字段包括代码、名称、最新价、涨跌幅、成交量、成交额和更新时间。
作业③——软科 2021 中国大学排名爬取
(1)F12 调试分析过程(含录制 Gif)
软科排名页面的院校数据并不是直接写在 HTML 里,而是由前端通过 Ajax 向后台接口请求来的。通过 F12 打开开发者工具:


- 在 Network 面板把过滤条件切换为
Fetch/XHR,刷新页面后即可看到页面发出的各类请求。 - 逐个查看这些请求,最终定位到官方数据接口
bcur(形如https://www.shanghairanking.cn/api/pub/v1/bcur?bcur_type=11&year=2021)。 - 点击该请求查看 Response,发现返回的是标准 JSON,其中的
data.rankings数组就是 2021 主榜全部 582 所院校,字段包括univNameCn(中文校名)、province(省市)、univCategory(类型)、score(总分)、ranking(排名)。
值得一提的是,最初我也尝试过去解析页面里加载的
payload.js静态文件,但发现它使用了 Brotli 压缩和非标准 JS 对象结构,解析成本很高。最终通过 F12 抓包找到这个干净的bcurJSON 接口,直接requests+json就能一次性拿到全量数据,既稳定又高效。
结论:直接调用 bcur 接口即可获取全部院校信息,无需 Selenium 翻页。
(2)核心代码
import requests
API_URL = "https://www.shanghairanking.cn/api/pub/v1/bcur" # 软科官方接口
def crawl_university_rank():
"""通过 F12 抓包找到的 API,一次性获取 2021 主榜全部院校数据"""
params = {"bcur_type": "11", "year": "2021"} # 主榜 + 2021 年
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"}
resp = requests.get(API_URL, params=params, headers=headers, timeout=15)
rankings = resp.json()["data"]["rankings"] # 全部 582 所院校
result = []
for item in rankings:
result.append((
int(item["ranking"]), # 排名(允许并列)
item["univNameCn"], # 中文校名
item["province"], # 省市
item["univCategory"], # 类型
float(item["score"]), # 总分
))
return result
# 之后用 sqlite3 写入 university_rank 表;并列排名不能用 rank 做主键,改用自增 id,代码略
(3)运行结果


运行后共入库 582 条院校数据,存储在 university.db 的 university_rank 表中,字段包括排名、学校、省市、类型、总分。注意软科主榜存在并列排名(如第 95 名有两所学校),因此 rank 不作为主键,而是用自增 id 做主键,完整保留了并列名次。
实验心得体会
各任务技术难点与收获
(一)关于作业①(天气爬虫)的心得:
这个任务让我体会到"所见即所得"的静态网页爬虫乐趣。静态网页的数据直接写在 HTML 里,解析的重点在于熟练使用 BeautifulSoup 进行节点定位。同时,在数据库设计上,我学会了使用 UNIQUE(city, date) 联合唯一约束配合 INSERT OR REPLACE,完美解决了程序重复运行时数据重复插入的问题。
(二)关于作业②(股票爬虫)的心得:
这个任务锻炼了我的 F12 抓包分析能力。我深刻理解了网页上的数据往往是前端通过 Ajax 向后端 API 请求来的,而不是直接写在页面源码里。在分析东方财富接口时,我学会了查看 Query 参数、理解 fields 字段的含义,并且处理了接口有时返回 JSONP 格式(带 callback 回调函数)的兼容性问题。这让我对 HTTP 协议和前后端 API 交互有了更深刻的理解。
(三)关于作业③(软科大学爬虫)的心得:
这是三个任务中最曲折的一个。起初我按部就班地去解析页面里加载的 payload.js 静态文件,却遭遇了返回乱码(Brotli 压缩)和无法用 json.loads 解析(非标准 JS 对象)的双重打击。这次碰壁让我明白:当一条路走不通时,回到 F12 抓包重新审视数据来源极其重要。最终我在 Network 面板的 XHR 请求里找到了官方的 bcur 接口,它直接返回全部 582 所院校的标准 JSON,用 requests 就能一次拿全。此外,我还踩了一个"并列排名"的坑——软科主榜允许并列名次,若把排名设为主键会导致并列院校被覆盖丢失,改用自增 id 做主键后才完整入库。这个从"硬啃 JS"到"找对接口"的过程,是我这次实验最大的收获。
整体总结与反思
本次作业不仅强化了我的 Python 爬虫编码规范(函数注释、变量命名、数据清洗等),更提升了我应对不同网页架构(静态 HTML、动态 API、复杂 JS 混淆)时的策略选择能力:
- 静态 HTML →
requests+BeautifulSoup(作业①); - 动态 API → F12 抓包 +
requests+json(作业②、作业③); - 复杂反爬/压缩数据 → 优先回到 F12 寻找更干净的 JSON 接口,而非硬啃 JS 或被迫上 Selenium。
在未来的学习中,我将继续深入学习 Scrapy 等高级框架,进一步提升爬虫的并发处理与工程化能力。

浙公网安备 33010602011771号