数据采集第三次作业
数据采集第三次作业
数据采集第三次作业:Scrapy 框架 + XPath + MySQL 数据库存储
Gitee 仓库链接:[https://gitee.com/vvvicky-chen/2026_crawl_project/tree/master/作业3]
实验环境:
| 项目 | 说明 |
|---|---|
| 操作系统 | Windows 11(64 位) |
| 编程语言 | Python 3.12 |
| 开发工具 | VS Code |
| 第三方库 | requests、beautifulsoup4、scrapy、pymysql、lxml、urllib |
本次作业共三个小作业,分别练习单/多线程爬取气象网图片、通过 F12 抓包分析东方财富 API 并用 Scrapy 解析入库、以及将中国银行外汇数据持久化存储到 MySQL 数据库中。
一、作业① 爬取中国气象网图片(单线程 + 多线程)
1)代码与运行结果
实验目标:爬取中国气象网( http://www.weather.com.cn )的图片,使用单线程和多线程两种方式,限制总页数为 9 页(学号尾数2位),总图片数为 109 张(学号尾数后3位)。
核心爬虫逻辑(单线程版本):
MAX_PAGES = 9 # 学号限制:09
MAX_IMAGES = 109 # 学号限制:109
START_URL = "http://www.weather.com.cn/radar/"
# 使用队列和循环逐页、逐图下载
while page_queue and len(visited_pages) < MAX_PAGES and img_count < MAX_IMAGES:
url = page_queue.pop(0)
# ... 解析页面提取图片链接 ...
for img in soup.find_all("img", src=True):
if img_count >= MAX_IMAGES:
break
# ... 逐张下载保存 ...
核心爬虫逻辑(多线程版本):
# 第一阶段:收集所有图片链接
while page_queue and len(visited_pages) < MAX_PAGES and len(all_image_urls) < MAX_IMAGES:
# ... 提取页面内的 img 标签 ...
# 第二阶段:使用 ThreadPoolExecutor 并发下载
with ThreadPoolExecutor(max_workers=WORKER_THREADS) as executor:
futures = {executor.submit(download_one, u): u for u in all_image_urls}
for idx, fut in enumerate(as_completed(futures), 1):
# ... 等待下载完成并保存 ...
运行结果:
-
单线程终端运行截图:
![1f7f72581d096a190657ebda20d04921]()
-
图片保存目录截图(共 109 个项目):
![5d4daf4717f0bf23990aba3c3505eb7d]()
-
多线程终端运行截图:
![5254a64db69e8179466d2c363692561a]()
-
图片保存目录截图(共 109 个项目):
![63ef6145f4e2650270f7085f850ee607]()
2)心得体会
本次实验最大的难点在于环境配置与限制条件的控制。首先,由于气象网首页的图片链接大多藏在 JS 或跳转子页面中,我通过调整 START_URL 到具体的雷达图页面,成功抓取到了真实图片。其次,在限制条件上,我将 MAX_PAGES 和 MAX_IMAGES 严格设置为学号对应的 9 页和 109 张,代码在抓满 109 张图片后会自动停止,符合要求。
在开发过程中,我遇到了 lxml 库在 Python 3.12 环境下无法正常加载的坑,最终通过将 BeautifulSoup 的解析器改为系统自带的 html.parser 成功绕过。此外,为了保证 109 张图片互不重名且不覆盖,我使用了 hashlib.md5 对图片 URL 进行加密命名。
在对比单线程和多线程的实现时,单线程代码逻辑直观,但每张图片都要等待上一个下载完成,遇到慢响应整体就会卡住;多线程利用线程池把下载任务拆分,IO 等待时间被重叠利用,下载 109 张图片的耗时明显缩短。这让我直观地感受到了多线程在 IO 密集任务中的巨大优势。
二、作业② 东方财富股票数据爬取(Scrapy + XPath + MySQL)
1)代码与实验步骤
实验目标:熟练掌握 Scrapy 中 Item、Pipeline 数据的序列化输出方法;使用 Scrapy 框架 + XPath + MySQL 数据库存储技术路线爬取股票相关信息。
核心代码(Item 与 Pipeline):
# items.py
class StockItem(scrapy.Item):
bStockNo = scrapy.Field() # 股票代码
sStockName = scrapy.Field() # 股票名称
fLatest = scrapy.Field() # 最新报价
fChangePct = scrapy.Field() # 涨跌幅
fChangeAmt = scrapy.Field() # 涨跌额
fVolume = scrapy.Field() # 成交量
fAmplitude = scrapy.Field() # 振幅
fHigh = scrapy.Field() # 最高
fLow = scrapy.Field() # 最低
fOpen = scrapy.Field() # 今开
fPrevClose = scrapy.Field() # 昨收
# pipelines.py (存入 MySQL)
class StockMySQLPipeline:
def open_spider(self, spider):
self.conn = pymysql.connect(host="localhost", user="vicky", password="******", database="homework3")
# ...
运行结果:
- MySQL 数据库入库截图:
![076658389375c531af6b856342f2ee86]()
- 结果显示截图:
![6272aceadecef7fa755ddd2ccaee33c6]()
2)心得体会
这次实验遇到了本次作业中最大的挑战——环境依赖冲突与路径套娃。最开始运行时,Scrapy 频繁报错,我依次解决了 cryptography、brotli 等底层依赖缺失的问题。然而在启动爬虫时,又遇到了 KeyError: 'Spider not found',经过排查发现是项目文件夹嵌套过深(套娃),导致 Scrapy 读取了外层的 scrapy.cfg 而找不到内层的爬虫。
为了解决这个问题,我重建了标准的项目结构,并编写了 run.py 脚本,利用 CrawlerProcess 强制指定项目配置并启动,彻底绕过了环境缓存问题。但在正式请求东方财富接口时,遭遇了服务器反爬(Remote end closed connection)。最终我采用了 urllib 直接伪装 Headers 发送请求,并用 pymysql 直连数据库写入,成功绕过了限制,将 60 条股票数据完整地序列化存入了 MySQL 表中。
三、作业③ 中国银行外汇牌价数据爬取
1)代码与运行结果
实验目标:使用 Scrapy 框架 + XPath + MySQL 存储技术路线,爬取中国银行网(https://www.boc.cn/sourcedb/whpj/)的外汇牌价数据,包含货币名称、TBP、CBP、TSP、CSP、时间。
核心代码(XPath 解析):
class BocSpider(scrapy.Spider):
name = "boc"
start_urls = ["https://www.boc.cn/sourcedb/whpj/"]
def parse(self, response):
for row in response.xpath('//table//tr[position()>1]'):
item = BocItem()
item["Currency"] = row.xpath("./td[1]/text()").get(default="").strip()
item["TBP"] = row.xpath("./td[2]/text()").get(default="").strip()
item["CBP"] = row.xpath("./td[3]/text()").get(default="").strip()
item["TSP"] = row.xpath("./td[4]/text()").get(default="").strip()
item["CSP"] = row.xpath("./td[5]/text()").get(default="").strip()
item["Time"] = row.xpath("./td[7]/text()").get(default="").strip()
if item["Currency"]:
yield item
运行结果:
- 终端打印的 WPS Excel 数据截图:
![3f3796a10b9a5b660a5c743528936d26]()
2)心得体会
通过前两个实验的磨炼,作业③的代码编写顺畅了许多,因为我掌握了如何在新建项目时规避“套娃”结构。中国银行的外汇页面是一个十分规整的静态表格,因此直接利用 Scrapy 的 XPath 提取 td[1] 到 td[7] 即可。
然而在最后展示数据时,由于之前多次测试导致数据库里存在旧数据,主键自增导致通过终端打印出来的数据行号是从 14 开始的。为了让结果展示更加干净、符合作业要求,我编写了 Python 脚本,用 pymysql 将 MySQL 中的数据导出为 CSV 文件,并用 WPS 打开展示。在检查数据时,我发现部分小币种(如文莱元、巴西雷亚尔)的现钞买入价为空白,这与中国银行原网页数据保持一致,证明爬虫抓取逻辑是完全正确的。
四、总结
本次数据采集大作业,从最基础的 requests 请求,到多线程并发下载图片,再到使用 Scrapy 框架搭建工程、编写 Pipeline、连接 MySQL 数据库,让我对网络爬虫的完整技术栈有了系统的认识。
最大的感触是:代码逻辑固然重要,但环境配置与工程结构同样不可忽视。 在作业②中,因为文件夹嵌套和环境残留,我耗费了大量的时间去排查路径问题。这也让我学会了在遇到报错时,不要盲目修改代码,而是静下心来看报错日志、分析文件层级结构。
此外,面对反爬和连接中断等突发情况,我学会了使用底层库(如 urllib)直接带 Header 请求,或者利用本地脚本中转导出数据。非常感谢这次实验,它不仅锻炼了我的代码能力,更极大地提升了我的问题排查与解决能力。








浙公网安备 33010602011771号