数据采集与融合技术作业一
作业1
仓库链接:https://gitee.com/jyppx000/crawl_project
作业①【结合flask】
要求:用requests和BeautifulSoup库方法定向爬取给定网址(http://www.shanghairanking.cn/rankings/bcur/2020)的数据,屏幕打印爬取的大学排名信息。
1.1 代码和图片
import re
import urllib.request
from bs4 import BeautifulSoup
from flask import Flask, render_template_string
class UniversityRankingScraper:
"""负责抓取网页内容并将数据解析为HTML表格"""
def __init__(self, url):
self.url = url # 存储排名页面的URL
self.table_html = None # 存储生成的HTML表格
def fetch_data(self):
"""发送HTTP请求并使用BeautifulSoup解析HTML数据"""
response = urllib.request.urlopen(self.url)
web_content = response.read()
soup = BeautifulSoup(web_content, 'html.parser')
return soup
def generate_html_table(self, soup):
"""从HTML页面提取排名数据,并生成一个带有表头的HTML表格"""
table = soup.find('table')
html_table = '<table border="1" cellspacing="0" cellpadding="5">\n'
html_table += ' <tr><th>排名</th><th>学校名称</th><th>省市</th><th>学校类型</th><th>总分</th></tr>\n'
for row in table.find_all('tr')[1:]:
cols = row.find_all('td')
rank = cols[0].get_text(strip=True)
school_name = re.sub(r'[A-Za-z]|(双一流|985|211)|/+', '', cols[1].get_text(strip=True)).strip()
province = cols[2].get_text(strip=True)
school_type = cols[3].get_text(strip=True)
score = cols[4].get_text(strip=True)
# 将提取到的信息添加到HTML表格中
html_table += f' <tr><td>{rank}</td><td>{school_name}</td><td>{province}</td><td>{school_type}</td><td>{score}</td></tr>\n'
html_table += '</table>'
self.table_html = html_table
return self.table_html
def get_html_table(self):
"""生成表格方法"""
soup = self.fetch_data() # 获取网页内容
return self.generate_html_table(soup) # 生成并返回HTML表格
class UniversityRankingApp:
"""创建一个简单的Flask应用,展示解析后的数据表格"""
def __init__(self, scraper):
self.scraper = scraper
self.app = Flask(__name__)
# 设置路由
@self.app.route('/')
def index():
table_html = self.scraper.get_html_table() # 获取HTML表格
return render_template_string(table_html) # 渲染表格到网页
def run(self):
self.app.run(debug=True)
# 入口
if __name__ == '__main__':
# 排名URL
url = "https://www.shanghairanking.cn/rankings/bcur/2021"
scraper = UniversityRankingScraper(url)
app = UniversityRankingApp(scraper)
app.run()
1.2 作业心得
- 巩固了面对结构复杂的网页时,如何使用标签选择和正则表达式进行精准的内容提取。
- 进一步提升了我的数据解析和清晰能力,如:学校名称中的“985”“211”等标签。
- 快速学习了如何将数据结构化,并通过Python将其转化为动态HTML展示出来,特别是在Flask框架中,使用
render_template_string
直接渲染HTML。 - 进一步巩固了我个人面向对象的能力,我通过将爬虫逻辑和Flask应用封装在类中,使代码结构清晰、易于扩展,同时我也是我以后写代码不断在靠拢的方向。
作业②【结合django】
要求:用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。
2.1 代码和图片
```settings.py``
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
"api.apps.ApiConfig" # 这里是注册的app
]
urls.py
urlpatterns = [
path("shop/",views.shop)
]
views.py
from django.shortcuts import render
from utils.handle import fetch_data
from utils.handle import parse_products
from utils.handle import extract_product_list
def shop(request):
"""执行爬取任务"""
url = r'https://search.dangdang.com/?key=%D3%B2%C5%CC&act=input'
data = fetch_data(url)
if data:
product_list = extract_product_list(data)
data = parse_products(product_list)
else:
data = []
return render(request,'index.html', {"data":data})
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品比价</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #f4f4f4;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h1>硬盘比价结果</h1>
<table>
<thead>
<tr>
<th>序号</th>
<th>价格 (¥)</th>
<th>商品名称</th>
</tr>
</thead>
<tbody>
{% if data %}
{% for item in data %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ item.0 }}</td>
<td>{{ item.1 }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">暂无数据</td>
</tr>
{% endif %}
</tbody>
</table>
</body>
</html>
utils/handle.py
import re
import requests
def fetch_data(url):
"""
发送GET请求并返回响应的HTML文本
:param url: 请求的网址
:return: 网页的HTML内容,如果请求失败则返回None
"""
try:
req = requests.get(url)
req.raise_for_status()
req.encoding = req.apparent_encoding
return req.text
except Exception as e:
print("Error in request:", e)
return None
def extract_product_list(data):
"""
使用正则表达式从网页数据中提取商品列表部分
:param data: 网页HTML内容
:return: 提取出的商品列表HTML片段
"""
match = re.search(r'<ul class="bigimg cloth_shoplist".*?>(.*?)</ul>', data, re.S)
if not match:
print("未找到商品列表")
return []
return match.group(1)
def parse_products(data):
"""
解析商品数据,提取商品的名称和价格
:param data: 商品列表的HTML片段
:return: 包含商品信息的列表,每个商品是一个元组(price, name)
"""
items = re.findall(r'<li.*?>(.*?)</li>', data, re.S)
products = []
for item in items:
price_match = re.search(r'<span class="price_n">¥(.*?)</span>', item)
title_match = re.search(r'title="(.*?)"', item)
if price_match and title_match:
price = price_match.group(1).strip()
name = title_match.group(1).strip()
products.append((price, name))
else:
products.append((None, None)) # 若找不到价格或名称,添加空值
return products
2.2 作业心得
-
仍然是巩固正则,对文本处理一个过程,当然也会存在匹配模式不准确导致无法提取数据,但是经过反复的调试,是能解决的
-
对处理异常更加熟练了 !
作业③:
要求:爬取一个给定网页( https://news.fzu.edu.cn/yxfd.htm)或者自选网页的所有JPEG和JPG格式文件
3.1代码和图片
import os
import re
import requests
from bs4 import BeautifulSoup
def create_directory(dir_path):
"""创建存储目录
:param dir_path: 目录路径
"""
if not os.path.exists(dir_path):
os.makedirs(dir_path)
def clean_filename(filename):
"""清理文件名,去掉不合法字符
:param filename: 原始文件名
:return: 清理后的文件名
"""
return re.sub(r'[<>:"/\\|?*]', '', filename) # 去除不合法字符
def download_image(url, save_path):
"""下载图片并保存到指定路径
:param url: 图片的URL地址
:param save_path: 保存路径
"""
try:
res = requests.get(url, 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",
})
with open(save_path, mode="wb") as fj:
fj.write(res.content)
print(f"下载成功:{save_path}")
except Exception as e:
print(f"下载失败:{url},错误信息:{e}")
def fetch_images_from_page(page_num):
"""从指定页面获取图片并返回图片链接和类型
:param page_num: 页码
:return: 图片链接和文件名的元组列表
"""
response = requests.get(
url=f"https://news.fzu.edu.cn/yxfd.htm?page={page_num}",
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",
}
)
soup = BeautifulSoup(response.text, "html.parser")
img_tags = soup.find_all("img") # 找到所有图片标签
image_info = [] # 存储图片信息的列表
for img in img_tags:
img_src = img.get("src") #
if img_src and img_src.startswith("/"): # 过滤掉不合法URL
url_path = f"https://news.fzu.edu.cn{img_src}"
file_name = clean_filename(img_src.split('/')[-1])
image_info.append((url_path, file_name))
return image_info
def save_images(image_info, jpeg_dir, other_dir):
"""根据图片类型保存图片到不同目录
:param image_info: 图片信息列表
:param jpeg_dir: JPEG图片存储目录
:param other_dir: 其他类型图片存储目录
"""
for url, file_name in image_info:
if file_name.lower().endswith(('.jpeg', '.jpg')): #
save_path = os.path.join(jpeg_dir, file_name) # JPEG文件路径
else:
save_path = os.path.join(other_dir, file_name) # 其他文件路径
download_image(url, save_path)
def main():
"""主函数,控制程序流程"""
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
JPEG_DIR = os.path.join(BASE_PATH, "jpeg_images")
OTHER_DIR = os.path.join(BASE_PATH, "other_images")
create_directory(JPEG_DIR)
create_directory(OTHER_DIR)
num_pages = int(input("请输入要爬取的页数:"))
for page in range(1, num_pages + 1):
print(f"开始爬取第 {page} 页...")
image_info = fetch_images_from_page(page)
save_images(image_info, JPEG_DIR, OTHER_DIR)
print("所有页面下载完成!")
if __name__ == "__main__":
main()
3.2 作业心得
- 再次熟悉正则和BeautifulSoup进行数据提取
- 处理文件下载时的异常情况
- 熟悉文件操作,os模块内置方法算是真记住了!