第二次作业:数据采集与融合技术

第二次作业:数据采集与融合技术实战(102402114)

学号: 102402114
姓名: 谢慧彬
Gitee 仓库链接: 【此处填入你的 Gitee 仓库地址】

本次作业共包含三个任务:① 中国气象网 7 日天气预报爬取;② 东方财富网股票信息爬取;③ 软科 2021 中国大学排名爬取。三个任务均使用 Python 编写,数据统一存储在 SQLite 数据库中。


爬虫代码实现与运行结果展示

作业①——中国气象网 7 日天气预报爬取

(1)F12 调试分析过程

为了获取天气数据,首先在浏览器中打开中国天气网北京页面( http://www.weather.com.cn/weather/101010100.shtml ),并按 F12 打开开发者工具:

  1. 在 Network(网络) 面板中选择 Doc 过滤标签,刷新网页后找到主文档请求 101010100.shtml。

wps_doc_0

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

wps_doc_1

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

wps_doc_2

  1. 可以清晰看到数据直接写在 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)运行结果

wps_doc_4

wps_doc_5

运行后共入库 21 条数据(3 个城市 × 7 天),存储在 weather.db 的 weather_7days 表中。


作业②——东方财富网股票信息爬取

(1)F12 调试分析过程

在爬取东方财富网股票数据时,最初在 Network 面板抓包并未直接找到目标数据。经过把过滤条件切换为 Fetch/XHR 并多次刷新页面后,成功抓到了名为 get?pn=1&pz=20... 的 API 请求。

分析该请求发现:

  1. 请求地址为 https://push2.eastmoney.com/api/qt/clist/get,返回的是标准 JSON 数据。

wps_doc_0

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

wps_doc_1

  1. 返回 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)运行结果

wps_doc_2

wps_doc_3

运行后共入库 298 条股票数据,存储在 stock.db 的 stock_data 表中,字段包括代码、名称、最新价、涨跌幅、成交量、成交额和更新时间。


作业③——软科 2021 中国大学排名爬取

(1)F12 调试分析过程(含录制 Gif)

软科排名页面的院校数据并不是直接写在 HTML 里,而是由前端通过 Ajax 向后台接口请求来的。通过 F12 打开开发者工具:
20261107-160752

wps_doc_1

  1. 在 Network 面板把过滤条件切换为 Fetch/XHR,刷新页面后即可看到页面发出的各类请求。
  2. 逐个查看这些请求,最终定位到官方数据接口 bcur(形如 https://www.shanghairanking.cn/api/pub/v1/bcur?bcur_type=11&year=2021)。
  3. 点击该请求查看 Response,发现返回的是标准 JSON,其中的 data.rankings 数组就是 2021 主榜全部 582 所院校,字段包括 univNameCn(中文校名)、province(省市)、univCategory(类型)、score(总分)、ranking(排名)。

值得一提的是,最初我也尝试过去解析页面里加载的 payload.js 静态文件,但发现它使用了 Brotli 压缩和非标准 JS 对象结构,解析成本很高。最终通过 F12 抓包找到这个干净的 bcur JSON 接口,直接 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)运行结果

wps_doc_2

wps_doc_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 等高级框架,进一步提升爬虫的并发处理与工程化能力。

posted @ 2026-11-09 00:17  Xx__X  阅读(3)  评论(0)    收藏  举报