数据采集实践第一次作业—陈宇新
代码路径:https://gitee.com/chenyuxin0328/data-collection/tree/master/作业1
作业1
动态网页爬取 - 2020 软科中国大学排名实验目标:
使用 requests 和 BeautifulSoup 库爬取 http://www.shanghairanking.cn/rankings/bcur/2020 的大学排名数据。
完整代码
import requests
from bs4 import BeautifulSoup
# 请求网址
url = "http://www.shanghairanking.cn/rankings/bcur/2020"
# 发送请求,获取响应
response = requests.get(url)
# 设置编码为utf-8,解决中文乱码问题
response.encoding = "utf-8"
# 解析响应内容
soup = BeautifulSoup(response.text, "html.parser")
# 找到包含大学排名信息的表格行
rows = soup.select(".rk-table tbody tr")
# 打印表头
print("排名\t学校名称\t省市\t学校类型\t总分")
# 遍历每一行数据
for row in rows:
# 获取排名
rank = row.select_one("td:nth-child(1)").text.strip()
# 获取学校名称(清理多余空格和换行)
name = row.select_one("td:nth-child(2)").text.strip().replace("\n", "").replace(" ", "")
# 获取省市
province = row.select_one("td:nth-child(3)").text.strip()
# 获取学校类型
type_ = row.select_one("td:nth-child(4)").text.strip()
# 获取总分
score = row.select_one("td:nth-child(5)").text.strip()
# 打印每一行数据
print(f"{rank}\t{name}\t{province}\t{type_}\t{score}")
关键代码解释
1)response = requests.get(url):用这个获取网页的内容,就像用代码打开网页看里面的东西。
2)soup = BeautifulSoup(...):把拿到的网页内容整理成容易处理的格式,方便后面找数据。
3)rows = soup.select(...):根据网页里的表格结构,精准找到存大学排名的那些行,不用看其他没用的内容。
4)row.select_one(...):在每一行里按位置找具体信息,比如第 1 个是排名、第 2 个是学校名,再把文字提取出来,去掉多余的空格。
运行结果
排名 学校名称 省市 学校类型 总分
1 清华大学 Tsinghua University双一流/985/211 北京 综合 852.5
2 北京大学 Peking University双一流/985/211 北京 综合 746.7
3 浙江大学 Zhejiang University双一流/985/211 浙江 综合 649.2
4 上海交通大学 Shanghai Jiao Tong University双一流/985/211 上海 综合 625.9
5 南京大学 Nanjing University双一流/985/211 江苏 综合 566.1
6 复旦大学 Fudan University双一流/985/211 上海 综合 556.7
7 中国科学技术大学 University of Science and Technology of China双一流/985/211 安徽 理工 526.4
8 华中科技大学 Huazhong University of Science and Technology双一流/985/211 湖北 综合 497.7
9 武汉大学 Wuhan University双一流/985/211 湖北 综合 488.0
10 中山大学 Sun Yat-sen University双一流/985/211 广东 综合 457.2
11 西安交通大学 Xi'an Jiaotong University双一流/985/211 陕西 综合 452.5
12 哈尔滨工业大学 Harbin Institute of Technology双一流/985/211 黑龙江 理工 450.2
13 北京航空航天大学 Beihang University双一流/985/211 北京 理工 445.1
14 北京师范大学 Beijing Normal University双一流/985/211 北京 师范 440.9
15 同济大学 Tongji University双一流/985/211 上海 理工 439.0
16 四川大学 Sichuan University双一流/985/211 四川 综合 435.7
17 东南大学 Southeast University双一流/985/211 江苏 综合 432.7
18 中国人民大学 Renmin University of China双一流/985/211 北京 综合 409.7
19 南开大学 Nankai University双一流/985/211 天津 综合 402.1
20 北京理工大学 Beijing Institute of Technology双一流/985/211 北京 理工 395.6
21 天津大学 Tianjin University双一流/985/211 天津 理工 390.3
22 山东大学 Shandong University双一流/985/211 山东 综合 387.9
23 厦门大学 Xiamen University双一流/985/211 福建 综合 383.3
24 吉林大学 Jilin University双一流/985/211 吉林 综合 379.5
25 华南理工大学 South China University of Technology双一流/985/211 广东 理工 379.4
26 中南大学 Central South University双一流/985/211 湖南 综合 378.6
27 大连理工大学 Dalian University of Technology双一流/985/211 辽宁 理工 365.1
28 西北工业大学 Northwestern Polytechnical University双一流/985/211 陕西 理工 359.6
29 华东师范大学 East China Normal University双一流/985/211 上海 师范 358.0
30 中国农业大学 China Agricultural University双一流/985/211 北京 农业 351.5
心得体会
这段代码就是个简单的网页爬取例子,思路很直接:先拿网页内容,再解析,最后把有用的数据抽出来。用 requests 拿内容,BeautifulSoup 帮忙找数据位置,还得处理一下中文乱码和多余的空格换行,不然看着乱。
我觉得爬东西关键是得看懂网页结构,比如用浏览器工具看看标签啥的。像这种结构清楚的网页,用 CSS 选择器找数据还挺快的。还有就是清理数据很重要,哪怕简单处理一下,结果也会清楚很多。
作业2
商城商品比价定向爬虫实验报告实验目标:使用 requests 和 re 库,设计一个定向爬虫,爬取自选商城上以“书包”为关键词搜索的商品名称和价格,并按指定格式输出。
完整代码
import requests
import re
import time
def crawl_meidebi_products():
site_domain = "https://www.meidebi.com"
search_term = "书包"
max_page_limit = 5
request_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
try:
print("正在测试目标站点连接...")
test_response = requests.get(site_domain, headers=request_headers, timeout=10)
print("站点连接测试通过。")
except requests.RequestException as conn_err:
print(f"站点连接测试失败: {conn_err}")
return
product_list = []
page_num = 1
while page_num <= max_page_limit:
current_page_url = f"{site_domain}/Search?keyword={search_term}&p={page_num}"
print(f"开始抓取第 {page_num} 页数据 -> 目标地址: {current_page_url}")
try:
page_response = requests.get(current_page_url, headers=request_headers, timeout=10)
page_response.raise_for_status()
page_response.encoding = page_response.apparent_encoding
page_html = page_response.text
except requests.RequestException as req_err:
print(f"第 {page_num} 页请求出错: {req_err}")
break
product_pattern = re.compile(
r'<li class="clearfix">.*?'
r'<span class="red price">\s*¥\s*([\d\.]+)\s*</span>.*?'
r'<h6><a href=".*?" target="_blank">(.*?)</a></h6>',
re.DOTALL
)
matched_products = product_pattern.findall(page_html)
if not matched_products:
print(f"第 {page_num} 页未匹配到商品数据,停止爬取。")
break
product_list.extend(matched_products)
if 'class="next' not in page_html:
print("已抓取到最后一页数据,停止爬取。")
break
page_num += 1
time.sleep(1)
print("\n" + "=" * 60)
print("没得比商品抓取结果汇总")
print("=" * 60)
print("序号\t商品价格\t商品名称")
print("-" * 60)
if product_list:
for seq, (price, product_name) in enumerate(product_list, start=1):
print(f"{seq}\t¥{price:<10}\t{product_name.strip()}")
else:
print("本次爬取未获取到任何商品信息。")
if __name__ == "__main__":
crawl_meidebi_products()
关键代码解读
1)正式爬取前先测试能否正常访问目标网站,就像出门前先看路况一样。如果连首页都打不开,后面的爬取也就没必要继续了,这里用try-except捕获连接错误,让程序更健壮。
try:
test_response = requests.get(site_domain, headers=request_headers, timeout=10)
print("站点连接测试通过。")
except requests.RequestException as conn_err:
print(f"站点连接测试失败: {conn_err}")
return
2)通过循环构造分页 URL(注意 URL 里的p={page_num}参数控制页码),每次爬完一页就暂停 1 秒,既避免给服务器造成压力,也降低被反爬的概率。max_page_limit限制最大爬取页数,防止无限循环。
while page_num <= max_page_limit:
current_page_url = f"{site_domain}/Search?keyword={search_term}&p={page_num}"
# 发送请求、处理响应...
page_num += 1
time.sleep(1) # 每页爬完休息1秒,友好爬取
3)通过分析网页源码,发现商品价格在span class="red price"标签里,商品名称在h6下的a标签里。正则表达式用([\d.]+)捕获价格数字,用(.*?)捕获商品名称,re.DOTALL参数让.能匹配换行符,确保能正确提取跨多行的内容。
product_pattern = re.compile(
r'<li class="clearfix">.*?'
r'<span class="red price">\s*¥\s*([\d\.]+)\s*</span>.*?'
r'<h6><a href=".*?" target="_blank">(.*?)</a></h6>',
re.DOTALL
)
matched_products = product_pattern.findall(page_html)
输出结果
正在测试目标站点连接...
站点连接测试通过。
开始抓取第 1 页数据 -> 目标地址: https://www.meidebi.com/Search?keyword=书包&p=1
开始抓取第 2 页数据 -> 目标地址: https://www.meidebi.com/Search?keyword=书包&p=2
开始抓取第 3 页数据 -> 目标地址: https://www.meidebi.com/Search?keyword=书包&p=3
开始抓取第 4 页数据 -> 目标地址: https://www.meidebi.com/Search?keyword=书包&p=4
开始抓取第 5 页数据 -> 目标地址: https://www.meidebi.com/Search?keyword=书包&p=5
============================================================
没得比商品抓取结果汇总
============================================================
序号 商品价格 商品名称
------------------------------------------------------------
1 ¥138.10 Lee 李牌校园通勤双肩书包
2 ¥51.19 360°散热透气!Comix 齐心 儿童超轻护脊卡通书包
3 ¥15.00 开学必备!Carany 卡拉羊 1-6年级减负防下坠儿童云朵书包 CX2190 18L
4 ¥74.75 HAZZYS 哈吉斯 男女童反光学生双肩书包
5 ¥31.61 1-3年级儿童护脊包包!Nohoo 诺狐 晨曦系列 儿童超轻减负护脊书包15L
6 ¥109.00 科巢 幼儿园儿童书包小号
7 ¥118.00 Carany 卡拉羊 1-6年级减负防下坠儿童书包 CX2842
8 ¥71.85 Carany 卡拉羊 幼儿园小中大班卡通书包 CX6312
9 ¥146.00 新蝶翼护脊背负设计!M&G 晨光 小学生护脊减负书包双肩包(6-14岁)
10 ¥32.00 新学期必备!Disney 迪士尼 钢铁侠/蜘蛛侠大容量减负护脊儿童书包 2款
11 ¥146.00 Deli 得力 小学生学院风英伦超轻防水护脊减负双肩书包 162(赠可拆卸腰托+同色笔袋+补习袋)
12 ¥83.28 Carany 卡拉羊 萌宠之家系列 儿童卡通书包 CX6305
13 ¥83.52 荣获德国IGR人体工学认证!Carany 卡拉羊 1-6年级减负防下坠儿童书包 CX2199
14 ¥107.10 KALA·Y 卡拉羊 星云系列 中学生双肩包书包25L 多色
15 ¥98.10 zoy zoii B18-B 幼儿园书包
16 ¥109.00 Carany 卡拉羊 小学生防下坠护脊大嘴书包 CX2587 藏青 22L
17 ¥149.00 Carany 卡拉羊 元气校园系列 学生书包 CX2553
18 ¥548.00 Gmt for kids 书包小学生儿童大容量礼物超轻护脊减负1-4年级男太空能力者Light
19 ¥548.00 Gmt for kids 书包小儿童背包护脊减负双肩包1-4年级女萌猫可折叠底板Trend
20 ¥648.00 Gmt for kids 书包小学生儿童大容量礼物超轻护脊减负1-4年级男女灵力萌猫Light
21 ¥591.02 新秀丽 双肩包男士电脑背包商务休闲通勤书包TT1 黑色 15.6英寸电脑
22 ¥80.90 海德 背包女大容量双肩包男15.6英寸笔记本电脑包旅行包国家地理书包
23 ¥787.02 Gmt for kids 书包小学生儿童超轻护脊大容量一二三年级男女童独角兽Light小版
24 ¥591.02 Gmt for kids 书包小学生男女超轻护脊减负儿童大容量书包1-2年级 寻梦独角兽
25 ¥886.02 Gmt for kids 儿童超轻护脊大容量书包 22L
26 ¥798.00 Gmt for kids 小学生初中生双肩包 男女生减负护脊书包 简约大容量背包 紫墨幻旅 护脊升级腰带款 26L
27 ¥19.70 Gmt for kids 初高中生书包 5-12年级大容量轻便男黑Magic
28 ¥591.02 Gmt for kids 大容量书包 超轻护脊减负 1-4年级
29 ¥886.02 Gmt for kids 儿童书包 22L 1-4年级 音速战机
30 ¥149.00 Gmt for kids 儿童护脊书包 4-9年级 26L 蓝羽梦女孩(品牌笔盒+防尘袋+礼盒)
31 ¥591.02 美旅 「新品」美旅大口袋书包男轻便减负大容量背包女初中生双肩包NJ8
32 ¥408.50 北极狐 FJALLRAVEN北极狐双肩包男女背包书包23561-667北极绿7L
33 ¥99.00 zoy zoii zoyzoii 儿童书包 欢乐苹果树
34 ¥69.00 Carany 卡拉羊 中学生书包 星云系列 5448丨深海蓝星云
35 ¥113.80 Gmt for kids 儿童护脊书包 4-9年级 蓝羽梦女孩
36 ¥841.20 Gmt for kids 初高中生书包 5-12年级大容量轻便男黑Magic
37 ¥43.90 Gmt for kids 小学生书包 1-4年级 音速战机Light
38 ¥551.02 凯思琳 Cathleen 双肩包超轻便书包潮包背包
39 ¥551.02 Gmt for kids 小学生书包 4-9年级 深海之息Trend
40 ¥858.00 Gmt for kids 小学生初中生书包 26L 4-9年级 蓝羽梦女孩Trend
41 ¥89.90 GOLF 双肩背包女士学生书包休闲运动旅行背包时尚通勤出游背包 款式6-果仁杏
42 ¥189.00 Gmt for kids 护脊儿童书包 1-4年级双肩 22L(赠 品牌笔盒*1)
43 ¥591.02 Gmt for kids 初中高中生书包 7-12年级 原力黑 30L(赠 品牌笔盒+礼盒包装)
44 ¥856.02 Gmt for kids 小学生书包 1-3-5年级 22L 音速战机(赠 品牌笔盒+零钱袋*1+防雨罩*1+礼盒包装)
45 ¥787.02 Gmt for kids 初高中生书包 7-12年级 白Trend pro(赠 品牌笔盒+礼盒包装)
46 ¥747.02 Gmt for kids 初高中生书包 4-9年级 女Trend max紫色含腰带
47 ¥1044.02 Gmt for kids 初高中生书包 5-12年级 Magic系列(赠笔盒)
48 ¥598.00 美旅 大口袋书包大容量双肩包 NG8
49 ¥11.90 新秀丽 男士电脑背包商务休闲通勤书包TT1 黑色
50 ¥886.02 Gmt for kids 初中高中生书包 7-12年级 黑Trend pro
心得体会
调试时踩了两个关键的坑:一是最初没配置User-Agent,请求直接被网站拦截,后来才意识到请求头是模拟正常访问的核心;二是正则表达式一开始没加re.DOTALL参数,导致跨换行的商品信息匹配不到,反复对比网页源码才找到问题。
另外,任务里设计的 “连接测试” 和 “分页终止判断” 很实用。前者能提前规避无效爬取,后者避免了因页数超限或无数据导致的程序冗余。最后加的 1 秒爬取间隔,也让我明白爬虫不仅要实现功能,还要考虑对目标服务器的影响,这是之前没太注意的细节。
作业3
网页图片定向爬虫实验报告实验目标:爬取福州大学新闻网“一线福大”板块(https://news.fzu.edu.cn/yxfd.htm)页面上的所有 .jpg, .jpeg, 或 .png 格式的图片,并下载保存在本地一个新建的文件夹中。
完整代码
import requests
from bs4 import BeautifulSoup
import os
import time
from urllib.parse import urljoin
# 要爬的6个网页地址
target_urls = [
"https://news.fzu.edu.cn/yxfd.htm",
"https://news.fzu.edu.cn/yxfd/1.htm",
"https://news.fzu.edu.cn/yxfd/2.htm",
"https://news.fzu.edu.cn/yxfd/3.htm",
"https://news.fzu.edu.cn/yxfd/4.htm",
"https://news.fzu.edu.cn/yxfd/5.htm"
]
# 图片保存的文件夹
save_dir = "fzu_images"
# 统计一共下了多少张图
image_count = 0
# 先建个文件夹放图片,没有就自动创建
if not os.path.exists(save_dir):
os.makedirs(save_dir)
print(f"创建了文件夹:{save_dir}")
def download_image(img_url, page_num):
"""下载单张图片"""
global image_count
try:
# 假装是浏览器访问
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0.0.0 Safari/537.36"
}
# 下载图片
response = requests.get(img_url, headers=headers, timeout=15)
response.raise_for_status() # 出错了就报错
# 弄个文件名,区分开不同页的图片
img_name = img_url.split("/")[-1]
if "." not in img_name:
img_name += ".jpg" # 没有后缀就加个.jpg
save_name = f"第{page_num}页_{image_count + 1}_{img_name}"
save_path = os.path.join(save_dir, save_name)
# 保存图片
with open(save_path, "wb") as f:
f.write(response.content)
image_count += 1
print(f"第{page_num}页:成功下载第{image_count}张图:{save_name}")
return True
except Exception as e:
print(f"第{page_num}页:下载失败 {img_url},原因:{e}")
return False
def crawl_page(page_url, page_num):
"""爬取一个页面里的图片"""
print(f"\n开始爬第{page_num}页:{page_url}")
try:
# 假装是浏览器访问页面
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0.0.0 Safari/537.36"
}
response = requests.get(page_url, headers=headers, timeout=15)
response.encoding = response.apparent_encoding # 解决乱码问题
# 解析页面,找图片
soup = BeautifulSoup(response.text, "html.parser")
# 找带img slow类的div,里面有我们要的图片
target_divs = soup.find_all("div", class_="img slow")
if not target_divs:
print(f"第{page_num}页没找到图片")
return
# 逐个下载图片
for div in target_divs:
img_tag = div.find("img")
if img_tag and img_tag.get("src"):
# 处理相对路径,变成完整网址
img_absolute_url = urljoin(page_url, img_tag["src"])
download_image(img_absolute_url, page_num)
time.sleep(1) # 慢点下,别太快
print(f"第{page_num}页爬完了")
except Exception as e:
print(f"第{page_num}页爬取失败:{e}")
if __name__ == "__main__":
print("开始爬福州大学的图片啦")
print("要爬的页面:", target_urls)
# 一页一页爬
for i, url in enumerate(target_urls):
page_num = i + 1 # 页码从1开始
crawl_page(url, page_num)
# 除了最后一页,每爬完一页等2秒
if i < len(target_urls) - 1:
print("等2秒再打下一页...")
time.sleep(2)
# 结束了,汇总一下
print("\n全部爬完啦!")
print(f"一共爬了{len(target_urls)}页,成功下载了{image_count}张图片")
print(f"图片都在这个文件夹里:{os.path.abspath(save_dir)}")
关键代码解释
1)target_urls:存了要爬的 6 个网页地址,都是福州大学相关页面,一页一页按顺序来
2)os.makedirs(save_dir):检查有没有叫fzu_images的文件夹,没有的话就自动建一个,方便存下载的图片
3)headers里的User-Agent:假装自己是浏览器在访问网页,不然有些网站会不让爬
4)BeautifulSoup:用来解析网页代码的工具,能帮我们从一堆杂乱的 html 里找到图片在哪
5)soup.find_all("div", class_="img slow"):专门找网页里带img slow这个类的 div,因为这些 div 里通常藏着我们要的图片
6)urljoin(page_url, img_tag["src"]):图片地址有时候是不完整的(相对路径),用这个把它拼成完整的网址,不然下不了
7)time.sleep(1):每下一张图片停 1 秒,怕爬太快被网站发现拦截
8)response.content:图片是二进制数据,用这个获取内容,再写到文件里就保存成图片了
输出结果

心得体会
这次写福州大学图片爬取代码,我学会了不少实用的东西。一开始不知道怎么找网页里的图片,后来用 BeautifulSoup 的 find_all 功能,精准定位到带特定类的 div,才顺利提取到图片地址。
中间也遇到过问题,比如有的图片地址不完整,下载时总出错,查资料后用 urljoin 把相对路径转成绝对路径,才解决了这个问题。还有加了 User-Agent 和 time.sleep,能避免被网站拦截。

浙公网安备 33010602011771号