作业1
网络数据爬取作业实践报告
作业一:大学排名信息爬取实践
1.1 作业代码与运行结果
核心代码
def get_university_ranking():
"""
爬取软科中国大学排名数据
"""
# 目标URL
url = "http://www.shanghairanking.cn/rankings/bcur/2020"
# 设置请求头,模拟浏览器访问
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
try:
# 发送HTTP请求
response = requests.get(url, headers=headers)
response.encoding = 'utf-8'
# 检查请求是否成功
if response.status_code == 200:
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 查找排名表格
table = soup.find('table', {'class': 'rk-table'})
if table:
# 提取表格数据
data = []
rows = table.find('tbody').find_all('tr')
for row in rows:
row_data = []
cells = row.find_all('td')
for i, cell in enumerate(cells):
text = cell.get_text().strip()
# 如果是学校名称列(通常是第2列),只提取前面的汉字部分
if i == 1: # 学校名称列
# 使用正则表达式只匹配汉字,遇到非汉字字符就停止
chinese_name = re.match(r'^[\u4e00-\u9fa5]+', text)
if chinese_name:
text = chinese_name.group()
else:
# 如果没有匹配到汉字,使用原始文本的前几个字符
text = text[:10] # 限制长度
row_data.append(text)
data.append(row_data)
# 打印表格
print("\n" + "=" * 80)
print("中国大学排名(2020年)")
print("=" * 80)
# 打印表头
print(f"{'排名':<8} {'学校名称':<12} {'省市':<8} {'学校类型':<10} {'总分':<10}")
print("-" * 80)
# 打印数据(前20条)
for i, row in enumerate(data[:20]):
if len(row) >= 5:
rank = row[0]
name = row[1]
province = row[2] if len(row) > 2 else ""
school_type = row[3] if len(row) > 3 else ""
score = row[4] if len(row) > 4 else ""
print(f"{rank:<8} {name:<12} {province:<8} {school_type:<10} {score:<10}")
print("-" * 80)
print(f"共爬取 {len(data)} 条数据")
return data
else:
print("未找到排名表格")
return None
else:
print(f"请求失败,状态码: {response.status_code}")
return None
except Exception as e:
print(f"爬取过程中出现错误: {e}")
return None
1.2 作业心得与体会
通过本次实践,我深入掌握了网页数据爬取的核心技术流程。在实现过程中,特别体会到BeautifulSoup库在HTML解析方面的强大功能,其简洁的API设计大大提高了开发效率。同时,对网页编码问题的处理也有了更深刻的理解,认识到正确设置编码对于中文网页数据提取的重要性。
作业二:商城商品比价爬虫实现
2.1 作业代码与运行结果
核心代码
def get_pdd_products():
"""
爬取拼多多书包商品信息
"""
# 搜索关键词
keyword = "书包"
# 拼多多搜索URL(移动端页面,结构相对简单)
url = "https://mobile.yangkeduo.com/search_result.html"
# 请求参数
params = {
'search_key': keyword,
'page': 1
}
# 设置请求头,模拟手机浏览器
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
try:
# 发送HTTP请求
response = requests.get(url, params=params, headers=headers, timeout=10)
response.encoding = 'utf-8'
print(f"请求状态码: {response.status_code}")
print(f"响应内容长度: {len(response.text)}")
if response.status_code == 200:
html_content = response.text
# 方法1:尝试从JSON数据中提取商品信息
# 拼多多通常会将数据放在window.rawData中
json_pattern = r'window\.rawData\s*=\s*({.*?});'
json_match = re.search(json_pattern, html_content, re.DOTALL)
if json_match:
try:
json_data = json_match.group(1)
data = json.loads(json_data)
print("成功提取JSON数据")
return parse_json_data(data)
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
# 方法2:如果JSON提取失败,使用正则表达式从HTML中提取
print("尝试使用正则表达式提取...")
return parse_html_with_regex(html_content)
else:
print(f"请求失败,状态码: {response.status_code}")
return None
except requests.exceptions.Timeout:
print("请求超时,请检查网络连接")
return None
except Exception as e:
print(f"爬取过程中出现错误: {e}")
return None
def parse_json_data(data):
"""
从JSON数据中解析商品信息
"""
products = []
try:
# 尝试不同的JSON路径来查找商品数据
stores = data.get('stores', {})
goods_list = stores.get('goodsList', [])
if goods_list:
for goods in goods_list:
try:
price = goods.get('normalPrice', '')
name = goods.get('goodsName', '')
if price and name:
products.append((price, name))
except:
continue
# 如果上面没找到,尝试其他路径
if not products:
items = data.get('items', [])
for item in items:
try:
price = item.get('price', '')
name = item.get('name', '')
if price and name:
products.append((price, name))
except:
continue
except Exception as e:
print(f"解析JSON数据失败: {e}")
return products
def parse_html_with_regex(html_content):
"""
使用正则表达式从HTML中提取商品信息
"""
products = []
try:
# 尝试匹配商品信息
# 模式1:匹配价格和商品名
pattern1 = r'"normalPrice":"(\d+\.?\d*)".*?"goodsName":"([^"]*)"'
matches1 = re.findall(pattern1, html_content)
# 模式2:匹配常见的商品展示格式
pattern2 = r'¥(\d+\.?\d*).*?>(.*?)<'
matches2 = re.findall(pattern2, html_content)
# 模式3:匹配更简单的格式
pattern3 = r'(\d+\.?\d*)元.*?([\u4e00-\u9fa5a-zA-Z0-9]+书包[\u4e00-\u9fa5a-zA-Z0-9]*)'
matches3 = re.findall(pattern3, html_content)
# 合并所有匹配结果
all_matches = matches1 + matches2 + matches3
for match in all_matches:
if len(match) >= 2:
price = match[0]
name = match[1]
# 清理名称
name = re.sub(r'<[^>]+>', '', name)
name = name.replace('\\', '').strip()
# 只保留包含"书包"关键词的商品
if '书包' in name:
products.append((price, name))
# 去重
unique_products = list(set(products))
except Exception as e:
print(f"正则表达式解析失败: {e}")
return unique_products
2.2 作业心得与反思
本次作业让我对正则表达式在文本提取中的应用有了全新认识。虽然正则表达式学习曲线较陡峭,但其在复杂文本模式匹配方面具有不可替代的优势。通过反复调试优化,最终实现了高精度的数据提取模式。
作业三:网页图片资源爬取
3.1 作业代码与运行结果
代码
import requests
import os
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import time
def download_images(url, save_folder='downloaded_images'):
"""
爬取网页中的所有图片并保存到本地文件夹
"""
# 创建保存图片的文件夹
if not os.path.exists(save_folder):
os.makedirs(save_folder)
# 设置请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
try:
# 发送HTTP请求
response = requests.get(url, headers=headers)
response.encoding = 'utf-8'
if response.status_code == 200:
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 查找所有图片标签
img_tags = soup.find_all('img')
# 支持的图片格式
valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
downloaded_count = 0
print("\n" + "=" * 60)
print("开始下载图片...")
print("=" * 60)
for i, img in enumerate(img_tags, 1):
# 获取图片URL
img_url = img.get('src') or img.get('data-src')
if img_url:
# 处理相对URL
img_url = urljoin(url, img_url)
# 检查图片格式
parsed_url = urlparse(img_url)
img_path = parsed_url.path.lower()
# 检查是否为支持的图片格式
is_valid_image = any(img_path.endswith(ext) for ext in valid_extensions)
if is_valid_image:
try:
# 下载图片
img_response = requests.get(img_url, headers=headers, timeout=10)
if img_response.status_code == 200:
# 生成文件名
img_name = os.path.basename(parsed_url.path)
if not img_name or '.' not in img_name:
img_name = f"image_{i}.jpg"
# 保存图片
file_path = os.path.join(save_folder, img_name)
# 如果文件名已存在,添加数字后缀
counter = 1
original_name = img_name
while os.path.exists(file_path):
name, ext = os.path.splitext(original_name)
img_name = f"{name}_{counter}{ext}"
file_path = os.path.join(save_folder, img_name)
counter += 1
with open(file_path, 'wb') as f:
f.write(img_response.content)
downloaded_count += 1
print(f"✓ 已下载: {img_name}")
# 添加短暂延迟,避免请求过快
time.sleep(0.1)
except Exception as e:
print(f"✗ 下载失败: {img_url} - 错误: {e}")
continue
print("=" * 60)
print(f"图片下载完成!共下载 {downloaded_count} 张图片")
print(f"图片保存在: {os.path.abspath(save_folder)}")
return downloaded_count
else:
print(f"请求失败,状态码: {response.status_code}")
return 0
except Exception as e:
print(f"爬取过程中出现错误: {e}")
return 0
# 主程序
if __name__ == "__main__":
# 使用给定的URL或自选URL
target_url = "https://news.fzu.edu.cn/yxfd.htm"
print("开始爬取网页图片...")
download_images(target_url)
3.3 作业心得与总结
本次作业让我全面掌握了网络资源下载的技术要点。特别是在文件流操作、本地存储管理和批量下载优化方面积累了宝贵经验。对HTTP请求响应过程的理解也更加深入。