作业①:

爬取天气数据

实验要求:在中国气象网(http://www.weather.com.cn)给定城市集的7日天气预报,并保存在数据库。
核心代码与结果:

class WeatherForecast:
    def __init__(self):
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"
        }
        self.cityCode = {"福州": "101230101"}

    def forecastCity(self, city):
        url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"
        req = urllib.request.Request(url, headers=self.headers)
        data = urllib.request.urlopen(req).read()
        data = UnicodeDammit(data, ["utf-8", "gbk"]).unicode_markup
        soup = BeautifulSoup(data, "lxml")
        ul = soup.find("ul", class_="t clearfix")
        lis = ul.find_all("li", recursive=False)
        for li in lis:
            date = li.select('h1')[0].text
            weather = li.select('p[class="wea"]')[0].text
            temp = li.select('p[class="tem"] span')[0].text + "/" + li.select('p[class="tem"] i')[0].text
            print(city, date, weather, temp)
            self.db.insert(city, date, weather, temp)

    def process(self):
        self.db = WeatherDB()
        self.db.openDB()
        self.forecastCity("福州")
        self.db.closeDB()

截屏2025-11-03 16.38.05

使用 urllib.request.Request 构造请求对象,为了顺利得到福州的天气预报数据,在请求时,必须添加User-Agent请求头来模拟浏览器,否则会请求失败。然后拼出目标 URL,发送请求并读取字节,并使用BeautifulSoup解析 HTML。
截屏2025-11-03 16.25
如图,我先定位 7 日预报列表,然后遍历它的直接子节点 li,一个li对应的就是一天,白天最高温在 span,夜间最低温在 i,拼成“高/低”,这样就实现了对天气预报数据的爬取。
心得:
这个任务的关键在于,需要准确定位天气预报所需的准确信息,并且需要能把我们需要的信息准确的提取出来。同时也必须添加请求头,如果不添加请求头,我们会被服务器拒绝访问。最后,编码问题也是无法忽视的,本次实验通过 BeautifulSoup 自带的 UnicodeDammit 模块解决了 gbk 和 utf-8 的自动检测问题,这是一个非常高效且显著的方法。

作业②

股票信息定向爬虫实验

实验要求:用requests和BeautifulSoup库方法定向爬取股票相关信息,并存储在数据库中。
核心代码与结果:

URL = "https://push2.eastmoney.com/api/qt/clist/get"
HEADERS = {"User-Agent": "Mozilla/5.0"}

# f12=代码, f14=名称, f2=最新价, f3=涨跌幅(%), f4=涨跌额, f5=成交量(手), f6=成交额(元)
FIELDS = "f12,f14,f2,f3,f4,f5,f6"
FS_HS_A = "m:0+t:6,m:0+t:13"
if __name__ == "__main__":
    page_size = 50      # 每页条数
    pages = 5           # 翻页页数
    rows = []           

    for p in range(1, pages + 1):
        # 关键查询参数:
        params = {
            "pn": p, "pz": page_size, "po": 1, "np": 1, "fltt": 2,
            "fid": "f3", "fs": FS_HS_A, "fields": FIELDS, "_": int(time.time() * 1000),
        }
        r = requests.get(URL, params=params, headers=HEADERS, timeout=10)
        text = r.text.strip()
        
        # 兼容 JSONP
        if not text.startswith("{"):
            m = re.search(r"\((\{.*\})\)\s*$", text)
            text = m.group(1) if m else text

        data = json.loads(text)
        diff = (data.get("data") or {}).get("diff", []) or []

        for d in diff:
            # 从字典取值并做类型转换
            code = d.get("f12"); name = d.get("f14")
            price = float(d.get("f2"))
            pct_chg = float(d.get("f3"))
            chg = float(d.get("f4"))
            vol = int(float(d.get("f5")))
            amount = float(d.get("f6"))

            if code:
                rows.append((code, name, price, pct_chg, chg, vol, amount))

    con = sqlite3.connect("stocks_min.db")
    cur = con.cursor()
    cur.execute("""
        CREATE TABLE IF NOT EXISTS stocks_min (
            code    TEXT PRIMARY KEY,
            name    TEXT,
            price   REAL,
            pct_chg REAL,
            chg     REAL,
            vol     INTEGER,
            amount  REAL
        );
    """)
    cur.executemany("""
        INSERT OR REPLACE INTO stocks_min
        (code, name, price, pct_chg, chg, vol, amount)
        VALUES (?, ?, ?, ?, ?, ?, ?);
    """, rows)
    con.commit()
    cur.execute("SELECT code,name,price,pct_chg,chg,vol,amount FROM stocks_min LIMIT 10;")
    for row in cur.fetchall():
        print(row)

    con.close()
    print(f"沪深A股 入库 {len(rows)} 条 stocks_min.db")

截屏2025-11-03 17.41.02

打开东方财富网https://quote.eastmoney.com/center/gridlist.html#hs_a_board
右键检查元素,进入网络搜索api,从中我们可以找到对应的数据。
截屏2025-11-03 17.58.48
发给网站查询参数,同时也要通过正则把JSON抠出来,从 JSON 数据中取出 data.diff 数组,然后提取出来每一条数据并塞入rows里,为之后进入数据库准备。
心得:
网络数据抓取不仅仅是能拿到数据,而且要拿到我们想要的数据,相比于全部数据一次性全爬取下来,这样的效率是低下的,我们更应该分析我们真正需要什么,学会爬取api返回的json数据,这一步在财经网站反爬设计中也是关键。

作业③

爬取中国大学2021主榜实验

实验要求:
爬取中国大学2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)所有院校信息。
核心代码与结果:

API = "https://www.shanghairanking.cn/api/pub/v1/bcur"
PARAMS = {"bcur_type": 11, "year": 2021} 
HEADERS = {
    "User-Agent": "Mozilla/5.0",
    "Referer": "https://www.shanghairanking.cn/rankings/bcur/2021",}

def fetch_rankings():
    r = requests.get(API, params=PARAMS, headers=HEADERS, timeout=20)
    r.raise_for_status()
    data = r.json()
    # 关键数据在 data.rankings
    lst = (data.get("data") or {}).get("rankings", [])
    rows = []
    for it in lst:
        rank = it.get("ranking") or it.get("rank")
        name = it.get("univNameCn") or it.get("univName")
        province = it.get("province")  # 省市
        utype = it.get("univCategory")  # 类型:综合/理工/… 
        score = it.get("score")
        if rank and name:
            rows.append((int(rank), str(name), str(province or ""), str(utype or ""), float(score or 0)))
    return rows

我们需要通过F12确定具体的数据来源,使用 F12点开Network,发现接口。它返回 JSON 数据,键 data.rankings 存放所有高校排名信息。
截屏2025-11-03 20.12.50

录屏2025-11-03 20.11

首先,我们发出请求,但要记得带请求头,不然会拒绝访问,接着从图中可以看到完整 JSON 对象,然后从JSON中挑选出我们需要的东西,剩下的也是放入row,最后存入数据库。
心得:
在本次任务中,更加深刻的体会到了该如何寻找api,在动态加载的网页结构中,分析api会比解析html更加有效快捷。同时也要api也会比html更加稳定,html的class很可能会因为网站改版发生变化,这会导致我们爬虫失败。最后,我们也要注意在js文件中的名称,如果设置不对也会导致爬取不到对应数据。

posted on 2025-11-03 20:42  林焜  阅读(14)  评论(0)    收藏  举报