102302133陈佳昕作业3

news/2025/11/24 0:11:33/文章来源:https://www.cnblogs.com/2025-project/p/19258997

作业①:

要求:指定一个网站,爬取这个网站中的所有的所有图片,例如:中国气象网(http://www.weather.com.cn)。实现单线程和多线程的方式爬取。
–务必控制总页数(学号尾数2位)、总下载的图片数量(尾数后3位)等限制爬取的措施。
输出信息: 将下载的Url信息在控制台输出,并将下载的图片存储在images子文件中,并给出截图。
Gitee文件夹链接:
单线程爬取:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/1/1.py
多线程爬取:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/1/2.py

1.单线程爬取

(1)代码

import urllib.request
from bs4 import BeautifulSoup
import osdef downloadImage(ID, src, tExt):try:imgName = 'download_bag\\' + ID + '.' + tExturllib.request.urlretrieve(src, imgName)print(f"已下载图片: {imgName}")except Exception as err:print(err)def initializeDownload():if not os.path.exists('download_bag'):os.mkdir('download_bag')fs = os.listdir('download_bag')if fs:for f in fs:os.remove('download_bag\\' + f)def spider(url):global page, count, max_img_countif count >= max_img_count:returnpage = page + 1print('Page', page, url)try:req = urllib.request.Request(url, headers=headers)resp = urllib.request.urlopen(req)html = resp.read().decode('gbk')soup = BeautifulSoup(html, 'lxml')lis = soup.select("ul[class='bigimg cloth_shoplist'] li[class^='line']")for li in lis:if count >= max_img_count:print(f"已达目标{max_img_count}张图,停止爬取当前页")breakimg = li.select_one('img')src = ''tExt = ''if img:# 优先使用 data-original 属性,如果没有则使用 srcif img.get('data-original'):src = urllib.request.urljoin(url, img['data-original'])else:src = urllib.request.urljoin(url, img['src'])p = src.rfind('.') if p >= 0:tExt = src[p + 1:]if tExt:count = count + 1ID = '%06d' % (count)downloadImage(ID, src, tExt)if count < max_img_count:nextUrl = ''links = soup.select("div[class='paging'] li[class='next'] a")for link in links:href = link['href']nextUrl = urllib.request.urljoin(url, href)if nextUrl:spider(nextUrl)except Exception as err:print(err)headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0'}
initializeDownload()
page = 0
count = 0
max_img_count = 133
spider(url='https://search.dangdang.com/?key=%CA%E9%B0%FC&category_id=10009684#J_tab')
print('Total %d pages,%d items' % (page, count))

(2)结果

8d12e33e-2a14-472a-b993-dcd87a94a915
9e6a2fb9-ca83-4f0a-bc75-958ab35ff7e0

(3)爬取的图片

5472df95-8a7e-43dc-a69a-a2471159209e

2.多线程爬取

(1)代码

import urllib.request
from bs4 import BeautifulSoup
import os
import threading
def downloadImage(ID, src, tExt):try:imgName = 'download\\' + ID + '.' + tExturllib.request.urlretrieve(src, imgName)print(f"已下载图片: {imgName}")except Exception as err:print(err)def initializeDownload():if not os.path.exists('download'):os.mkdir('download')fs = os.listdir('download')if fs:for f in fs:os.remove('download\\' + f)def spider(url):global page, count, threads, max_img_countif count >= max_img_count:returnpage = page + 1print('Page', page, url)try:req = urllib.request.Request(url, headers=headers)resp = urllib.request.urlopen(req)html = resp.read().decode('gbk')soup = BeautifulSoup(html, 'lxml')lis = soup.select("ul[class='bigimg cloth_shoplist'] li[class^='line']")for li in lis:if count >= max_img_count:print(f"已达目标{max_img_count}张图,停止爬取当前页")breakimg = li.select_one('img')src = ''tExt = ''if img:# 优先使用 data-original 属性,如果没有则使用 srcif img.get('data-original'):src = urllib.request.urljoin(url, img['data-original'])else:src = urllib.request.urljoin(url, img['src'])p = src.rfind('.') # 找到最后一个"."的索引if p >= 0:tExt = src[p + 1:]if tExt:count = count + 1ID = '%06d' % (count)T = threading.Thread(target=downloadImage, args=[ID, src, tExt])T.start()threads.append(T)if count < max_img_count:nextUrl = ''links = soup.select("div[class='paging'] li[class='next'] a")for link in links:href = link['href']nextUrl = urllib.request.urljoin(url, href)if nextUrl:spider(nextUrl)except Exception as err:print(err)headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0'}
initializeDownload()
threads = []
page = 0
count = 0
max_img_count = 133
spider(url='https://search.dangdang.com/?key=%CA%E9%B0%FC&category_id=10009684#J_tab')
for T in threads:T.join()
print('Total %d pages,%d items' % (page, count))

(2)结果

12218a73-d0ce-47bc-b1ba-c5f8d665933f
1c4513df-2b88-4ff7-a0cc-6c6803f151e1

(3)爬取的图片

91717e9d-dfd1-445f-aade-de86d797f74c

3.心得体会

通过单线程与多线程爬取图片的实践,我清晰感受到多线程爬取提高的效率。

作业②

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取股票相关信息。
候选网站:东方财富网:https://www.eastmoney.com/
输出信息:MySQL数据库存储和输出格式如下:

股票代码 股票名称 最新报价 涨跌幅 涨跌额 成交量 成交额 振幅 最高 最低 今开 昨收
688093 N世华 28.47 10.92 26.13万 7.6亿 22.34 32.0 28.08 30.20 17.55

表头英文命名例如:序号id,股票代码:bStockNo……,由同学们自行定义设计
Gitee文件夹链接:
BankItem:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/2/1.py
Bank_Spider:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/2/2.py
pipelines:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/2/3.py

1.代码

(1)StockItem类

import scrapy
class StockItem(scrapy.Item):id = scrapy.Field()stock_code = scrapy.Field()stock_name = scrapy.Field()current_price = scrapy.Field()change_percent = scrapy.Field()change_amount = scrapy.Field()volume = scrapy.Field()amplitude = scrapy.Field()highest_price = scrapy.Field()lowest_price = scrapy.Field()open = scrapy.Field()previous_close = scrapy.Field()pass

(2)Stock_Spider类

import scrapy
from demo.items import StockItem
class Stock_Spider(scrapy.Spider):name = 'stock_spider'allowed_domains = ['www.eastmoney.com']start_urls = ['https://quote.eastmoney.com/center/gridlist.html#hs_a_board']def parse(self,response):try:stocks = response.xpath("//tbody//tr")for stock in stocks[1:]:item = StockItem()item["stock_code"] = stock.xpath(".//td[2]//text()").extract_first()item["stock_name"] = stock.xpath(".//td[3]//text()").extract_first()item["current_price"] = stock.xpath(".//td[5]//text()").extract_first()item["change_percent"] = stock.xpath(".//td[6]//text()").extract_first()item["change_amount"] = stock.xpath(".//td[7]//text()").extract_first()item["volume"] = stock.xpath(".//td[8]//text()").extract_first()item["amplitude"] = stock.xpath(".//td[10]//text()").extract_first()item["highest_price"] = stock.xpath(".//td[11]//text()").extract_first()item["lowest_price"] = stock.xpath(".//td[12]//text()").extract_first()item["open"] = stock.xpath(".//td[13]//text()").extract_first()item["previous_close"] = stock.xpath(".//td[14]//text()").extract_first()yield itemexcept Exception as err:print(err)

(3)pipelines.py

import sqlite3
class StockPipeline(object):def open_spider(self, spider):print("open_spider")self.conn = sqlite3.connect('stocks.db')self.cursor = self.conn.cursor()self.cursor.execute("DROP TABLE IF EXISTS stocks")sql = """CREATE TABLE stocks(id INTEGER PRIMARY KEY AUTOINCREMENT,stock_code VARCHAR(255),stock_name VARCHAR(255),current_price VARCHAR(255),change_percent VARCHAR(255),change_amount VARCHAR(255),volume VARCHAR(255),amplitude VARCHAR(255),highest_price VARCHAR(255),lowest_price VARCHAR(255),open VARCHAR(255),previous_close VARCHAR(255))"""self.cursor.execute(sql)self.conn.commit()print("数据库表创建成功")def close_spider(self, spider):print("close_spider")self.conn.commit()self.conn.close()def process_item(self, item, spider):stock_code = item.get('stock_code', '')stock_name = item.get('stock_name', '')current_price = item.get('current_price', '')change_percent = item.get('change_percent', '')change_amount = item.get('change_amount', '')volume = item.get('volume', '')amplitude = item.get('amplitude', '')highest_price = item.get('highest_price', '')lowest_price = item.get('lowest_price', '')open_price = item.get('open', '')previous_close = item.get('previous_close', '')try:sql = """INSERT INTO stocks (stock_code, stock_name, current_price, change_percent, change_amount, volume, amplitude, highest_price, lowest_price, open, previous_close) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"""self.cursor.execute(sql, [stock_code, stock_name, current_price, change_percent, change_amount,volume, amplitude, highest_price, lowest_price, open_price, previous_close])self.conn.commit()print(f"成功插入数据: {stock_code} {stock_name}")except Exception as err:print(f"插入数据失败: {err}")return item

(4)middlewares.py

import time
from selenium import webdriver
from scrapy.http import HtmlResponseclass SeleniumMiddleware:def process_request(self, request, spider):driver = webdriver.Edge()try:driver.get(request.url)time.sleep(5)data = driver.page_sourcefinally:driver.quit()return HtmlResponse(url=request.url, body=data.encode('utf-8'), encoding='utf-8', request=request)

(5)settings.py

ITEM_PIPELINES = {"demo.pipelines.StockPipeline": 300,
}
DOWNLOADER_MIDDLEWARES = {'demo.middlewares.SeleniumMiddleware': 543,
}

2.结果

071f1640-296d-4bd2-8c49-310c62d129ab
67f81fe6-951a-42c9-8fcc-a6063f2958da

3.心得体会

起初,爬取不到数据,后来发现股票数据是通过JavaScript动态加载的,直接访问页面获取不到数据,所以结合了Selenium来爬取。通过实验,我深刻认识到高效数据采集系统的构建不仅需要精准的页面解析能力,更需注重数据管道的完整性与稳定性。

作业③:

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。
候选网站:中国银行网:https://www.boc.cn/sourcedb/whpj/
输出信息:

Currency TBP CBP TSP CSP Time
阿联酋迪拉姆 198.58 192.31 199.98 206.59 11:27:14

Gitee文件夹链接:
StockItem类:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/3/1.py
Stock_Spider类:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/3/2.py
pipelines:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/3/3.py
middlewares:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/3/4.py
settings:https://gitee.com/chen-jiaxin_fzu/2025_crawl_project/blob/master/作业3/3/5.py

1.代码

(1)BankItem类

import scrapy
class BankItem(scrapy.Item):id = scrapy.Field()currency = scrapy.Field()tbp = scrapy.Field()cbp = scrapy.Field()tsp = scrapy.Field()csp = scrapy.Field()time = scrapy.Field()pass

(2)Bank_Spider类

import scrapy
from demo.items import BankItem
class Bank_Spider(scrapy.Spider):name = "bank_spider"allowed_domains = ["www.boc.cn"]start_urls = ["https://www.boc.cn/sourcedb/whpj/"]def parse(self, response):try:rows = response.xpath('//table//tr')for row in rows[2:-2]:item = BankItem()item['currency'] = row.xpath("./td[1]//text()").extract_first()item['tbp'] = row.xpath("./td[2]//text()").extract_first()item['cbp'] = row.xpath("./td[3]//text()").extract_first()item['tsp'] = row.xpath("./td[4]//text()").extract_first()item['csp'] = row.xpath("./td[5]//text()").extract_first()item['time'] = row.xpath("./td[8]//text()").extract_first()yield itemexcept Exception as err:print(err)

(3)pipelines.py

import sqlite3
class BankPipeline(object):def __init__(self):self.id_counter = 1def open_spider(self, spider):print("open_spider")self.conn = sqlite3.connect('bank.db')self.cursor = self.conn.cursor()# 如果表存在则删除self.cursor.execute("DROP TABLE IF EXISTS bank")# 创建表sql = """CREATE TABLE bank ( id       INTEGER PRIMARY KEY AUTOINCREMENT, currency VARCHAR(255), tbp      VARCHAR(255), cbp      VARCHAR(255), tsp      VARCHAR(255), csp      VARCHAR(255), time     VARCHAR(255)) """self.cursor.execute(sql)self.conn.commit()print("数据库表创建成功")def close_spider(self, spider):print("close_spider")self.conn.commit()self.conn.close()def process_item(self, item, spider):currency = item.get('currency', '')tbp = item.get('tbp', '')cbp = item.get('cbp', '')tsp = item.get('tsp', '')csp = item.get('csp', '')time = item.get('time', '')try:sql = "INSERT INTO bank (currency, tbp, cbp, tsp, csp, time) VALUES (?, ?, ?, ?, ?, ?)"self.cursor.execute(sql, [currency, tbp, cbp, tsp, csp, time])self.conn.commit()print(f"成功插入数据: {currency}")except Exception as err:print(f"插入数据失败: {err}")return item

2.结果

82692d54-d4ec-4612-b0fd-5ddc45455fdf
9fcf386e-0ae6-4647-a500-aadccf7c5502

3.心得体会

通过本次基于Scrapy框架结合XPath解析与MySQL数据库的外汇数据爬取实践,我深刻体会到数据采集系统中技术组件协同工作的重要性——Scrapy的Item类为数据字段提供了标准化容器,确保了数据结构的清晰性与可维护性;XPath选择器的精准设计直接决定了表格数据的提取效率,而Pipeline机制则通过分层式数据处理流水线实现了数据的清洗、验证与序列化输出,特别是MySQL数据库的连接管理、批量插入,显著提升了数据存储的可靠性与系统容错能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/974376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSAPP 处理器体系结构

处理器体系结构 CISC 与 RISC 指令集 CISC:复杂指令计算机 (如x86-64) RISC:精简指令计算机 (如RISC-V) RISC 相较于CISC指令数量少得多,编码长度固定,寻址没有变址寄存器和伸缩因子,对机器级程序实现细节可见...…

AI协助 一周打造「七巧板益智小游戏」:从零高效开发教学工具

AI协助 一周打造「七巧板益智小游戏」:从零高效开发教学工具 一个“教学痛点”引发的开发冲动。本文讲述如何利用Copilot在一周内快速开发一个面向小学数学教学的七巧板益智小游戏,涵盖需求分析、技术选型、核心算法…

【MCP系列】用 MCP 扩展 AI 编辑器:从零开发一个自己的MCP服务

【MCP系列】用 MCP 扩展 AI 编辑器:从零开发一个自己的MCP服务本文MCP协议,手把手教你构建一个自己的MCP Server,在AI编辑器实现通过自然语言指令调用自己写的工具脚本。随着 AI 编辑器(如 Copilot、通义灵码、Tra…

VB6版MP3文件信息编辑器 - 开源研究系列文章 - 个人小作品

VB6版MP3文件信息编辑器 - 开源研究系列文章 - 个人小作品Posted on 2025-11-24 00:00 lzhdim 阅读(0) 评论(0) 收藏 举报 这次整理VB6编写的MP3文件的ID3v1信息编辑器。该应用比较简单,主要是对于ID3v1信…

手把手教你用 React + Zustand 打造 Windows 风格可拖拽,缩放,多窗口 Modal 组件

手把手教你用 React + Zustand 打造 Windows 风格可拖拽,缩放,多窗口 Modal 组件记录仿Windows风格的可拖拽、缩放、多窗口 Modal 组件的实现还在为每个弹窗写重复的拖拽、缩放、Z轴代码而烦恼吗?还在复制粘贴 onMo…

ImGui Learn Data Day 1

ImGui Learn data Day 1ImGui::Begin("Hello Gui");static float u = 0;static bool an = 0;if (ImGui::CollapsingHeader("Settings"))//展开条{//如果点击就展开或者关闭ImGui::SliderFloat(&qu…

OI 笑传 #34

夜の東側今天是 bct Day4,赛时 \(75+30+40+0=115\),rk 54。 T1 挂分原因仍未知,直接原因是没有大样例,然后是用数据结构维护的贪心,比较恶心。 赛时比较爆炸,T1 连想带调用了 3h,导致比较简单的 T2,T3,T4 没有…

【MCP系列】介绍一个我自己开发的MCP工具:MCP Shipit

【MCP系列】介绍一个我自己开发的MCP工具:MCP Shipit介绍一个我自己开发的MCP工具:MCP Shipit,欢迎来github提issue,star!在AI编辑器日益普及的今天,我们可以通过自定义工具来扩展AI的能力。本文将介绍如何从零开…

第34天(简单题中等题 数据结构)

打卡第三十四天 1道简单题+两道中等题题目:思路:哈希表+遍历 代码: class Solution{ public:int maxSum(vector<int>& nums){unordered_map<int,int> hash;int ans = -1;for(int x: nums){int maxd…

3. Gin RESTful API 开发

3. Gin RESTful API 开发 3.1 RESTful API简介 3.1.1 RESTful API 定义REST(Representational State Transfer,表现层状态转换)是一种软件架风格、设计风格,而不是一种标准。它提供了一组设计原则和约束条件,主要用…

说课逐字稿2

尊敬的各位评委老师: 大家好!今天我说课的题目是《健康数据小哨兵——循环选择嵌套》。 面对海量健康数据,如何从“人工低效核对”跨越到“智能精准监测”?这是本课要解决的核心问题。我将从分析策略、教学过程、教…

Codeforces Round 1066 (Div. 1 + Div. 2) 做题记录

Dashboard - Codeforces Round 1066 (Div. 1 + Div. 2) - Codeforces Problem - A - Codeforces 题意: 平衡数组定义为:若 \(x\) 存在,则存在 \(x\) 个 \(x\),求给定数组至少删去多少数变成平衡数组。 题解: 若 \…

2025.11.23总结

一些思考和建议 1. 现状分析:从“稀缺”到“饱和”的本质 过去的“高工价”源于互联网和移动互联网的爆炸性增长,对代码的渴求是海量的。那时,一个能实现功能的程序员就是稀缺资源。 现在的“不稀缺”,准确地说,是…

字符串常见操作

字符串常见操作查找: find 字符是否包含在字符串中,在就返回这个子字符串开始位置的下标,否则就返回-1 count 返回出现的次数,返回某个子字符串在整个字符串中出现的次数,没有就返回0 index 和index一样但是会报…

广州比较靠谱的留学中介

广州比较靠谱的留学中介一、广州留学中介怎么选?这些疑问你有吗?作为从事12年国际教育规划师,我经常被广州的学生和家长问到:广州的留学中介哪家更靠谱?申请英国研究生,广州哪家中介成功率更高?广州本地口碑最好…

SpringBoot 2.x - 3.x 踩坑记录

一、现状:JDK17 SpringBoot 2.6.8 Gradle 7.6二、目标:JDK17 gradle 8.10.2 SpringBoot 3.5.6 无漏洞版本三、问题: 1. import javax.*报错 原因:SpringBoot 2.x 使用 javax 规范,SpringBoot 3.x 使用 jakarta 规…

广州比较好的留学机构

广州比较好的留学机构一、广州留学机构怎么选?这五个问题你考虑过吗?作为一位拥有十年经验的国际教育规划师,我经常被广州的学生和家长问及如何挑选留学中介。在选择过程中,许多人会陷入纠结:广州留学机构哪家更靠…

AtCoder Beginner Contest 433 题解

只写了 A-F。A - Happy Birthday! 4 开局就绷不住了,晚上脑子有点不清醒直接暴力 check 到 \(10^7\) 没想到直接过了。代码。但是正解还是要推式子的,设 \(k\) 年后为答案,则有 \(X + k = Z(Y + k)\),移项后得到 \…