数据采集第一次作业

学号:102402135
姓名:王伟浩
课程:数据采集与融合技术
作业链接:第一次作业

作业①:

undefined 要求:用requests和BeautifulSoup库方法定向爬取给定网址的数据,屏幕打印爬取的大学排名信息。

一.实验

1. 代码设计思路

本程序使用 requests 获取目标网页,再利用 BeautifulSoup 解析 HTML,通过 CSS 选择器定位大学排名表格,提取排名、学校名称、省市、学校类型和总分,最后按照表格形式输出结果。

2. 可能遇到的问题

爬取过程中主要需要注意网页编码和 HTML 结构问题。中文网页如果编码设置不正确可能出现乱码,同时网页结构发生变化也可能导致选择器无法正确获取数据,因此程序对网页编码和数据列数进行了处理。

3.关键代码分析

response = requests.get(
    url,
    headers=headers
)

(1)发送网页请求: 使用 requests.get() 向目标网址发送 GET 请求,并设置 User-Agent 请求头模拟浏览器访问。获取网页后设置 UTF-8 编码,保证中文内容能够正常解析。

soup = BeautifulSoup(
    response.text,
    "html.parser"
)

(2)解析网页内容: 使用 BeautifulSoup 对获取到的 HTML 源代码进行解析,并指定 html.parser 作为解析器,为后续查找网页中的排名数据做准备。

rows = soup.select(
    "tbody tr"
)

(3)定位排名表格: 使用 CSS 选择器 tbody tr 定位大学排名表格中的数据行,每个 tr 对应一条大学排名信息。

for row in rows:

    cols = row.find_all("td")

    if len(cols) >= 5:

        rank = cols[0].text.strip()
        name = cols[1].text.strip()
        province = cols[2].text.strip()
        category = cols[3].text.strip()
        score = cols[4].text.strip()

(4)遍历并提取大学信息: 遍历所有排名数据行,通过 find_all("td") 获取当前行中的各个单元格,再按照网页中的字段顺序提取排名、学校名称、省市、学校类型和总分。strip() 用于清除文本前后的空格和换行。

print(
    "{:<8}{:<15}{:<10}{:<10}{:<10}"
    .format(
        rank,
        name,
        province,
        category,
        score
    )
)

(5)格式化输出结果: 使用 format() 设置各字段的显示宽度,将提取到的大学信息按照统一格式输出到终端,方便查看最终的爬取结果。

完整代码:


import requests
from bs4 import BeautifulSoup

目标网址

url = "http://www.shanghairanking.cn/rankings/bcur/2020"

设置请求头,模拟浏览器访问

headers = {
"User-Agent": "Mozilla/5.0"
}

def get_university_rank():
# 发送请求
response = requests.get(
url,
headers=headers
)

设置网页编码

response.encoding = "utf-8"

创建 BeautifulSoup 对象

soup = BeautifulSoup(
response.text,
"html.parser"
)

查找排名表格中的所有行

rows = soup.select("tbody tr")

输出表头

print("=" * 75)
print(
"{:<8}{:<18}{:<12}{:<12}{:<10}".format(
"排名",
"学校名称",
"省市",
"学校类型",
"总分"
)
)
print("=" * 75)

遍历学校信息

for row in rows:
cols = row.find_all("td")

if len(cols) >= 5:

获取排名

rank = cols[0].get_text(
" ",
strip=True
)

获取学校中文名称

找到学校名称所在的标签

name_tag = cols[1].find(
"span",
class_="name-cn"
)

if name_tag:
name = name_tag.get_text(
strip=True
)
else:
# 如果网页结构发生变化,
# 则只取第一个文本内容
name = cols[1].get_text(
" ",
strip=True
).split(" ")[0]

获取省市信息

province_text = cols[2].get_text(
" ",
strip=True
)

删除办学标签

province = province_text

for tag in [
"双一流",
"985",
"211"
]:
province = province.replace(
tag,
""
)

province = province.strip()

获取学校类型

category = cols[3].get_text(
" ",
strip=True
)

获取总分

score = cols[4].get_text(
" ",
strip=True
)

输出学校信息

print(
"{:<8}{:<18}{:<12}{:<12}{:<10}".format(
rank,
name,
province,
category,
score
)
)

if name == "main":
get_university_rank()

运行结果:

a28705f337d49863d5d50970d0781fb5

二.心得体会

通过本次实验,我熟悉了使用 requests 获取网页以及使用 BeautifulSoup 解析网页的基本方法。通过实际爬取大学排名数据,我了解到网络爬虫不仅需要发送网页请求,还需要根据网页的 HTML 结构准确定位和提取目标数据。

作业②:

undefined 要求:用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。此实验使用当当网

一.实验

1. 代码设计思路

本程序选择当当网作为爬取对象,使用 requests 库获取“书包”关键词的商品搜索页面,再利用 re 库通过正则表达式提取商品名称和价格信息。程序对爬取到的商品进行去重,并将结果在屏幕上按照序号、价格和商品名的形式输出,同时保存到文本文件中。

2. 可能遇到的问题

爬取过程中主要需要注意网页编码、商品 HTML 结构以及商品重复问题。由于网页内容包含中文,因此需要正确设置网页编码;同时通过正则表达式匹配商品名称和价格时,需要根据网页实际结构设计匹配规则,最后对商品名称进行去重,避免重复数据影响结果。

3.关键代码分析

# (1)设置关键词和爬取数量
KEYWORD = "书包"
MAX_COUNT = 60

http = urllib3.PoolManager()

headers = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/155.0.0.0 Safari/537.36"
    ),
    "Referer": "https://www.dangdang.com/"
}

(1)设置爬取参数: 设置搜索关键词为“书包”,最多获取 60 条商品信息,同时设置请求头模拟浏览器访问,减少网页拒绝请求的情况。

# (2)生成搜索页面地址并获取网页
keyword = quote(KEYWORD)

url = (
    "https://search.dangdang.com/"
    "?key=" + keyword +
    "&act=input"
    "&page_index=" + str(page)
)

response = http.request(
    "GET",
    url,
    headers=headers,
    timeout=10.0
)

(2)获取搜索页面: 使用 quote() 对中文关键词进行 URL 编码,然后根据关键词和页码生成当当网搜索页面地址,通过 GET 请求获取网页内容。

# (3)设置网页编码并获取 HTML 内容
if response.status != 200:
    return ""

html = response.data.decode(
    "gbk",
    errors="ignore"
)

return html

(3)处理网页内容: 判断服务器返回的状态码是否为 200,确认网页正常获取后,将网页内容按照 GBK 编码进行解码,得到可以进行正则表达式匹配的 HTML 文本。

# (4)使用正则表达式定位商品
li_pattern = re.compile(
    r'<li\s+ddt-pit="[^"]+"\s+class="[^"]*"\s+id="[^"]*"\s*>'
    r'(.*?)'
    r'</li>',
    re.S
)

items = li_pattern.findall(html)

(4)定位商品信息: 使用正则表达式查找网页中的商品 li 标签,将每一个商品的 HTML 内容提取出来,为后续获取商品名称和价格做准备。

# (5)提取商品价格和名称
price_match = re.search(
    r'<span\s+class="price_n"\s*>\s*'
    r'&yen;?\s*([\d.]+)'
    r'\s*</span>',
    item,
    re.S
)

name_match = re.search(
    r'<p\s+class="name"\s+name="title"[^>]*>'
    r'\s*<a[^>]*>'
    r'(.*?)'
    r'</a>',
    item,
    re.S
)

(5)提取商品信息: 分别通过正则表达式匹配商品价格和商品名称,其中价格从 price_n 标签中提取,商品名称从商品名称对应的 a 标签中提取。

# (6)清理商品名称并保存数据
name = re.sub(
    r'<[^>]+>',
    '',
    name
)

name = re.sub(
    r'\s+',
    ' ',
    name
)

name = name.strip()

products.append(
    {
        "name": name,
        "price": price
    }
)

(6)处理并保存商品数据: 去除商品名称中的 HTML 标签以及多余的空格和换行,然后将商品名称和价格保存到列表中,方便后续统一输出。

# (7)去除重复商品
for product in products:

    duplicate = False

    for old_product in all_products:

        if old_product["name"] == product["name"]:
            duplicate = True
            break

    if not duplicate:
        all_products.append(product)

(7)商品去重: 遍历已经获取的商品信息,通过比较商品名称判断当前商品是否已经存在,只有不存在重复商品时才将其加入最终结果列表。

# (8)输出商品名称和价格
for i, product in enumerate(all_products, 1):

    print(
        "{:<5} {:<55} {:>12}".format(
            i,
            product["name"],
            "¥" + product["price"]
        )
    )

(8)格式化输出: 使用 enumerate() 为商品添加序号,再利用 format() 将序号、商品名称和价格按照固定格式输出到屏幕,形成清晰的商品信息表格。

完整代码:


import requests
import re
from urllib.parse import quote

============================================================

当当网“书包”商品比价定向爬虫

使用:requests + re

最多爬取:60项

============================================================

KEYWORD = "书包"
MAX_COUNT = 60

headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/155.0.0.0 Safari/537.36"
),
"Referer": "https://www.dangdang.com/"
}

def get_page(page):
"""
获取当当网搜索结果页面
"""

keyword = quote(KEYWORD)

url = (
"https://search.dangdang.com/"
"?key=" + keyword +
"&act=input"
"&page_index=" + str(page)
)

try:
# 使用 requests 发送 GET 请求
response = requests.get(
url,
headers=headers,
timeout=10
)

print("正在访问:", url)
print("状态码:", response.status_code)
print("网页长度:", len(response.content))

if response.status_code != 200:
return ""

当当网页使用 GBK 编码

html = response.content.decode(
"gbk",
errors="ignore"
)

return html

except Exception as e:
print("访问页面失败:", e)
return ""

def parse_products(html):
"""
使用正则表达式提取商品名称和价格
"""

products = []

========================================================

第一步:找到商品列表

========================================================

li_pattern = re.compile(
r'<li\s+ddt-pit="["]+"\s+class="["]"\s+id="[^"]"\s>'
r'(.
?)'
r'',
re.S
)

items = li_pattern.findall(html)

for item in items:

----------------------------------------------------

提取商品价格

----------------------------------------------------

price_match = re.search(
r'<span\s+class="price_n"\s>\s'
r'¥?\s([\d.]+)'
r'\s
',
item,
re.S
)

if not price_match:
continue

price = price_match.group(1).strip()

----------------------------------------------------

提取商品名称

----------------------------------------------------

name_match = re.search(
r'<p\s+class="name"\s+name="title"[^>]>'
r'\s
<a[^>]>'
r'(.
?)'
r'',
item,
re.S
)

if not name_match:
continue

name = name_match.group(1)

删除 HTML 标签

name = re.sub(
r'<[^>]+>',
'',
name
)

清理多余空格和换行

name = re.sub(
r'\s+',
' ',
name
)

name = name.strip()

if name:
products.append(
{
"name": name,
"price": price
}
)

return products

============================================================

主程序

============================================================

print("=" * 80)
print(" 当当网“书包”商品比价定向爬虫")
print("=" * 80)

print("关键词:", KEYWORD)
print("最多爬取:", MAX_COUNT, "项")
print()

all_products = []

最多检查10页

for page in range(1, 11):

达到60项后停止

if len(all_products) >= MAX_COUNT:
break

print("-" * 80)
print("正在爬取第", page, "页")

html = get_page(page)

if not html:
print("网页获取失败")
continue

products = parse_products(html)

print("本页解析到:", len(products), "项")

if len(products) == 0:
print("本页没有解析到商品,停止爬取。")
break

--------------------------------------------------------

添加商品,并进行去重

--------------------------------------------------------

for product in products:

duplicate = False

for old_product in all_products:

if old_product["name"] == product["name"]:
duplicate = True
break

if not duplicate:
all_products.append(product)

if len(all_products) >= MAX_COUNT:
break

============================================================

输出结果

============================================================

print()
print("=" * 90)
print(" 爬取结果")
print("=" * 90)

按照作业要求输出:

序号、价格、商品名

print(
"{:<8} {:<15} {}".format(
"序号",
"价格",
"商品名"
)
)

print("-" * 90)

for i, product in enumerate(all_products, 1):

name = product["name"]

终端显示时限制商品名称长度

if len(name) > 55:
name = name[:55] + "..."

print(
"{:<8} {:<15} {}".format(
i,
product["price"],
name
)
)

print("-" * 90)

print(
"实际爬取商品数量:",
len(all_products)
)

print("=" * 90)

============================================================

保存结果

============================================================

with open(
"dangdang_shubao.txt",
"w",
encoding="utf-8"
) as f:

f.write("当当网“书包”商品爬取结果\n")
f.write("=" * 80 + "\n")

for i, product in enumerate(all_products, 1):

f.write(
"{}. {} ¥{}\n".format(
i,
product["name"],
product["price"]
)
)

print()
print("结果已经保存到:dangdang_shubao.txt")

运行结果:

图2

二.心得体会

通过本次实验,我熟悉了使用 requests 获取商城网页以及使用 re 正则表达式提取网页数据的方法。通过实际爬取当当网“书包”商品信息,我进一步了解了如何根据网页结构设计正则表达式,并对爬取到的数据进行清理、去重和保存。通过本次实践,我对商品信息定向爬取的基本流程有了更加直观的认识。

作业③:

undefined 要求:爬取一个 给定网站 或者自选网页的所有JPEG、JPG或PNG格式图片文件

一.实验

1. 代码设计思路

本程序以福州大学新闻网页面作为爬取对象,使用 requests 获取网页 HTML 内容,再利用 BeautifulSoup 查找页面中的图片标签,获取图片文件地址。程序判断图片格式后发送请求下载图片,并统一保存到指定文件夹中。

2. 可能遇到的问题

爬取过程中主要需要注意图片地址可能使用相对路径,以及网页中可能存在不同格式的图片。程序需要将相对地址转换为完整 URL,并根据图片扩展名筛选 JPEG、JPG 和 PNG 格式,避免下载其他无关文件。

3.关键代码分析

# (1)获取目标网页
response = requests.get(
    url,
    headers=headers
)

response.encoding = response.apparent_encoding

soup = BeautifulSoup(
    response.text,
    "html.parser"
)

(1)获取并解析网页: 使用 requests.get() 获取目标网页内容,根据网页实际编码设置响应编码,再使用 BeautifulSoup 对 HTML 页面进行解析。

# (2)查找网页中的图片标签
images = soup.find_all("img")

(2)查找图片: 使用 find_all("img") 查找网页中的所有图片标签,从而获取页面中的图片资源。

# (3)获取图片地址
src = img.get("src")

if not src:
    continue

img_url = urljoin(
    url,
    src
)

(3)获取图片地址: 从 img 标签中获取 src 属性。如果图片没有地址则跳过,并使用 urljoin() 将相对图片地址转换成完整的图片 URL。

# (4)筛选指定格式的图片
if not re.search(
    r"\.(jpg|jpeg|png)(\?.*)?$",
    img_url,
    re.I
):
    continue

(4)筛选图片格式: 使用正则表达式判断图片 URL 是否以 .jpg、.jpeg 或 .png 结尾,只保留符合实验要求的图片格式。

# (5)下载并保存图片
image_response = requests.get(
    img_url,
    headers=headers,
    timeout=10
)

if image_response.status_code == 200:

    with open(
        save_path,
        "wb"
    ) as f:

        f.write(image_response.content)

(5)下载图片: 对筛选出的图片地址再次发送请求,获取图片二进制数据,并使用 open() 以二进制写入方式保存到指定文件夹中。

完整代码:


import os
import re
import requests
from urllib.parse import urljoin

============================================================

网页图片爬虫

功能:爬取网页中的 JPEG、JPG、PNG 图片并保存到文件夹

============================================================

目标网页

URL = "https://news.fzu.edu.cn/yxfd.htm"

图片保存目录

SAVE_DIR = "images"

设置请求头,模拟浏览器访问

HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/155.0.0.0 Safari/537.36"
)
}

def get_page():
"""
获取目标网页的 HTML 源代码
"""

try:
response = requests.get(
URL,
headers=HEADERS,
timeout=10
)

print("正在访问:", URL)
print("状态码:", response.status_code)
print("网页长度:", len(response.content))

if response.status_code != 200:
print("网页访问失败")
return ""

根据网页实际编码设置

response.encoding = response.apparent_encoding

return response.text

except Exception as e:
print("网页访问失败:", e)
return ""

def get_image_urls(html):
"""
使用正则表达式提取网页中的图片地址
"""

查找 img 标签中的 src 属性

pattern = re.compile(
r'<img[^>]+src="'["']',
re.I
)

image_urls = pattern.findall(html)

将相对地址转换为完整 URL

full_urls = []

for image_url in image_urls:

full_url = urljoin(
URL,
image_url
)

只保留 JPEG、JPG、PNG 图片

if re.search(
r'.(jpg|jpeg|png)(?:?.*)?$',
full_url,
re.I
):
if full_url not in full_urls:
full_urls.append(full_url)

return full_urls

def download_images(image_urls):
"""
下载图片并保存到本地 images 文件夹
"""

创建保存目录

os.makedirs(
SAVE_DIR,
exist_ok=True
)

success_count = 0

print()
print("=" * 70)
print("开始下载图片")
print("=" * 70)

for index, image_url in enumerate(
image_urls,
1
):

try:
response = requests.get(
image_url,
headers=HEADERS,
timeout=10
)

if response.status_code != 200:
print(
"[失败]",
index,
image_url
)
continue

从 URL 中获取文件扩展名

extension_match = re.search(
r'.(jpg|jpeg|png)(?:?.*)?$',
image_url,
re.I
)

if extension_match:
extension = "." + extension_match.group(1).lower()
else:
extension = ".jpg"

使用序号作为文件名,避免原文件名重复

filename = "image_{:03d}{}".format(
index,
extension
)

filepath = os.path.join(
SAVE_DIR,
filename
)

保存图片

with open(
filepath,
"wb"
) as f:
f.write(response.content)

success_count += 1

print(
"[成功]",
index,
"->",
filename
)

except Exception as e:
print(
"[失败]",
index,
"->",
e
)

return success_count

def main():
"""
主程序
"""

print("=" * 70)
print(" 网页图片爬取程序")
print("=" * 70)

获取网页源代码

html = get_page()

if not html:
return

提取图片地址

image_urls = get_image_urls(html)

print()
print("网页中找到 JPEG/JPG/PNG 图片:",
len(image_urls),
"张")

if len(image_urls) == 0:
print("没有找到符合要求的图片")
return

下载图片

success_count = download_images(
image_urls
)

print()
print("=" * 70)
print("图片爬取完成")
print("=" * 70)
print("发现图片数量:", len(image_urls))
print("成功下载数量:", success_count)
print("保存文件夹:", SAVE_DIR)
print("=" * 70)

if name == "main":
main()

###**运行结果**

图3

图4

二.心得体会

通过本次实验,我熟悉了网页图片资源的获取和保存方法,了解了如何从 HTML 页面中查找 img 标签并提取图片地址。在实践过程中,我也认识到网页中的图片地址不一定都是完整 URL,需要对相对路径进行处理,同时还需要根据文件扩展名筛选目标图片。最终程序能够将网页中的 JPEG、JPG 和 PNG 图片保存到指定文件夹,加深了我对网页资源爬取过程的理解。

作业总结

通过本次作业,我完成了大学排名、商城商品和网页图片三类数据的采集,进一步熟悉了 requests、BeautifulSoup 和正则表达式的使用。实验过程中也遇到了网页编码、数据定位和图片路径等问题,通过实际调试让我更加了解了网页数据采集的基本流程。
整体来看,本次作业让我掌握了从网页获取数据到解析、筛选和保存的基本方法,也提高了自己分析网页结构和解决爬虫运行问题的能力。

posted @ 2026-10-16 21:37  好的id  阅读(8)  评论(0)    收藏  举报