2024数据采集与融合技术实践-作业3

news/2024/11/14 2:43:05/文章来源:https://www.cnblogs.com/starryship/p/18540991

一、中国气象网单线程与多线程爬取图片

码云仓库:作业3/task1 · 曹星才/2022级数据采集与融合技术 - 码云 - 开源中国

(一)步骤

爬取网站:https://p.weather.com.cn/tqxc/index.shtml

1.1 单线程方式爬取

step1:设置为单线程方式爬取,settings.py中注设置最大并发请求数量CONCURRENT_REQUESTS=1

step2:找到图片对应的网站,发送请求

# 方法:生成初始请求并发送到目标网址
def start_requests(self):# 循环遍历目标网站的前 5 页for page in range(1, 6):# 第一页的 URL 结构不同,需要单独处理if page == 1:url = "https://p.weather.com.cn/tqxc/index.shtml"else:url = f"https://p.weather.com.cn/tqxc/index_{page}.shtml"# 使用 scrapy.Request 发送请求,获取页面内容# 该请求的响应将由 'parse' 方法处理yield scrapy.Request(url=url, callback=self.parse)

step3:对请求得到的网页进行解析,使用img_urls = selector.xpath('//img/@src')获取该页的所有图片url,使用yield scrapy.Request(url=img_src, callback=self.download)逐个url调用download图片下载函数

# 方法:解析天气页面的 HTML 响应
def parse(self, response, *args, **kwargs):data = response.body.decode('utf-8')  # 将响应的字节数据解码为 UTF-8 字符串# 使用 Scrapy 的 Selector 类来解析解码后的 HTML 数据selector = scrapy.Selector(text=data)# 提取页面中的所有图像 URLimg_urls = selector.xpath('//img/@src')# 遍历所有提取的图像 URLfor img_url in img_urls:img_src = img_url.extract()  # 获取每个图像 URL 的字符串形式print(img_src)  # 打印图像 URL(用于调试)if img_src:  # 检查图像 URL 是否有效# 发送请求下载图像,下载完成后调用 'download' 方法yield scrapy.Request(url=img_src, callback=self.download)

step4:处理图片的下载请求,创建WeatherItem实例,存储图像二进制数据,将获取到的二进制数据传给item

# 方法:处理图像下载请求
def download(self, response):item = WeatherItem()  # 创建一个 WeatherItem 实例,用于存储图像二进制数据# 从响应中提取图像的二进制内容img_binary = response.body# 将图像的二进制数据存入 itemitem["img_binary"] = img_binary# 使用 yield 传递 item,将数据传递给数据管道或输出yield item

step5:WeatherItem这只用接收图片的二进制数据,传给pipelines

class WeatherItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()img_binary = scrapy.Field()

step6:二进制数据传到pipelines,对数据进行保存,保存为JPG格式的图片

# 定义一个处理爬取数据的管道类
class WeatherPipeline:count = 0  # 定义一个类变量,用于记录下载的图像数量# 处理每个传入的 item 对象def process_item(self, item, spider):# 每当处理一个 item 时,将计数器加 1WeatherPipeline.count += 1# 构造保存图像的路径# 每张图像使用递增的数字作为文件名,并保存在 "imgs" 文件夹中downloadPath = f"imgs/{WeatherPipeline.count}.jpg"# 以二进制写模式打开文件fobj = open(downloadPath, "wb")# 将图像的二进制数据写入文件fobj.write(item["img_binary"])# 关闭文件对象,确保数据被正确保存fobj.close()# 打印下载完成的信息,包括图像的字节数print("下载完毕:", len(item["img_binary"]), "字节")# 返回 item 对象,以便在 Scrapy 框架中继续处理return item

step7scrapy crawl wea -s LOG_ENABLED=False运行项目

step8:得到单线程爬取的结果

1.2 多线程方式爬取

step9:设置为多线程方式爬取,settings.py中设置最大并发请求数量CONCURRENT_REQUESTS=32(其它数字也行)

step10scrapy crawl wea -s LOG_ENABLED=False运行项目

step11:得到多线程爬取的结果

(二)心得

在这次使用 Scrapy 进行中国气象网单线程与多线程爬取图片爬取的实验中,通过单线程和多线程两种方式分别爬取了天气网站的图片,积累了很多经验和心得。

首先,在单线程方式下,设置了 CONCURRENT_REQUESTS=1,保证每次只发送一个请求,逐一处理每个页面的图像。这种方式的优势在于操作简单、易于调试,可以清晰地控制每一步的执行过程。通过 scrapy.Request 发送请求并解析网页,获取图片 URL 后,再逐个请求下载图片。在下载过程中,我利用 Scrapy 的 WeatherItem 存储图片的二进制数据,并通过管道保存为 JPG 格式的图片。这种方法确保了图片能够按顺序保存,便于后期的管理。

然而,单线程的效率较低,特别是当网页图片较多时,下载速度会变得较慢。为了解决这个问题,我尝试了多线程方式。在 settings.py 中将 CONCURRENT_REQUESTS 设置为 32,这样 Scrapy 就能同时处理多个请求,大大提高了抓取和下载的效率。多线程方式虽然能加速爬取过程,但也增加了资源占用,可能会导致服务器负载过高,需要合理设置并发数。

总结来说,单线程适合小规模爬取或需要严格控制爬取速度的场景,而多线程则适合大规模爬取,可以显著提高效率。通过这次实验,我不仅加深了对 Scrapy 框架的理解,也对如何根据爬取任务的需求选择合适的并发策略有了更清晰的认识。

二、股票相关信息爬取

码云仓库:作业3/task2 · 曹星才/2022级数据采集与融合技术 - 码云 - 开源中国

(一)步骤

step1:找到对应网站的url(https://quote.eastmoney.com/center/gridlist.html#hs_a_board),发送请求

# 定义初始请求的方法
def start_requests(self):# 遍历 start_urls 列表中的每个 URLfor url in self.start_urls:# 生成 Scrapy 请求,并指定回调函数 parse 处理响应yield scrapy.Request(url=url, callback=self.parse)

step2:直接解析网页可以看到,输出的data没有我们想要的信息,说明这个网站是js动态渲染的,这个时候就需要加入selenium

step3:在middlewares.py中设置中间件,在StockDownloaderMiddleware中添加我们的配置

为什么选择下载器中间件

  1. 处理动态内容:Selenium 是一个浏览器自动化工具,适合用来加载和处理由 JavaScript 渲染的动态网页内容。通过在下载器中间件中使用 Selenium,你可以在请求发送到目标网站之前或之后加载页面并提取数据,然后再将处理后的响应交给 Scrapy 引擎或 Spider。
  2. 灵活性:将 Selenium 集成到下载器中间件中,可以灵活地控制哪些请求需要用 Selenium 处理,比如对一些特定的动态网页,其他的普通网页则仍然用 Scrapy 的默认下载器来处理。
class StockDownloaderMiddleware:# Scrapy 中的下载中间件类,用于自定义处理请求和响应def __init__(self):# 初始化方法,配置并启动一个无头(headless)Chrome 浏览器chrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--headless')  # 运行无头模式,不打开浏览器窗口chrome_options.add_argument('--disable-gpu')  # 禁用 GPU(适用于某些无头模式的情况)self.driver = webdriver.Chrome(options=chrome_options)  # 创建一个 Chrome 浏览器实例@classmethoddef from_crawler(cls, crawler):# 用于创建中间件实例,并连接 spider_opened 信号s = cls()  # 创建中间件实例crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)  # 连接爬虫打开时的信号return s  # 返回中间件实例def process_request(self, request, spider):# 处理每个请求的方法self.driver.implicitly_wait(10)  # 设置隐式等待时间为 10 秒self.driver.get(request.url)  # 使用 Selenium 加载网页body = self.driver.page_source  # 获取网页加载后的 HTML 源代码# 创建并返回一个 HtmlResponse 对象,以提供给 Scrapy 进行后续解析return HtmlResponse(url=request.url,body=body,encoding='utf-8',request=request)def process_response(self, request, response, spider):# 处理响应的方法,返回处理后的响应对象return response  # 返回原始响应,未进行任何修改def process_exception(self, request, exception, spider):# 处理请求或下载过程中的异常pass  # 未处理异常,继续异常链的处理def spider_opened(self, spider):# 当爬虫被打开时调用的方法spider.logger.info("Spider opened: %s" % spider.name)  # 记录日志,指示爬虫已打开def spider_closed(self, spider):# 当爬虫关闭时调用的方法self.driver.quit()  # 关闭浏览器以释放资源spider.logger.info("Browser closed for spider: %s" % spider.name)  # 记录日志,指示浏览器已关闭

settings.py中配置:

step4:然后我们就可以顺利的获取到网页的动态数据了,观察html结构

step5:在parse中对数据进行解析

def parse(self, response):# 将响应的字节数据解码为 UTF-8 字符串data = response.body.decode('utf-8')# 使用 Scrapy 的 Selector 类解析 HTML 数据selector = scrapy.Selector(text=data)# 使用 XPath 定位包含股票数据的表格body = selector.xpath("//table[@id='table_wrapper-table']")# 提取表格中的所有行(<tr> 元素),忽略第一个没用的trs = body.xpath("//tr")[1:]# 遍历每个表格行,提取所需数据for tr in trs:# 创建一个 StockItem 实例,用于存储提取的数据item = StockItem()# 提取每一列的数据,并使用 XPath 获取相应的文本内容xuHao = tr.xpath("./td[1]/text()").get()  # 序号guPiaoDaiMa = tr.xpath("./td[2]//text()").get()  # 股票代码guPiaoNingCheng = tr.xpath("./td[3]//text()").get()  # 股票名称zuiXingBaoJia = tr.xpath("./td[5]//text()").get()  # 最新报价zhangDieFu = tr.xpath("./td[6]//text()").get()  # 涨跌幅zhangDieE = tr.xpath("./td[7]//text()").get()  # 涨跌额chengJiaoLiang = tr.xpath("./td[8]//text()").get()  # 成交量zhenFu = tr.xpath("./td[10]//text()").get()  # 振幅zuiGao = tr.xpath("./td[11]//text()").get()  # 最高价zuiDi = tr.xpath("./td[12]//text()").get()  # 最低价jinKai = tr.xpath("./td[13]//text()").get()  # 今开价zuoShou = tr.xpath("./td[14]//text()").get()  # 昨收价# 将提取的数据存入 item 对象的相应字段item['xuHao'] = xuHaoitem['guPiaoDaiMa'] = guPiaoDaiMaitem['guPiaoNingCheng'] = guPiaoNingChengitem['zuiXingBaoJia'] = zuiXingBaoJiaitem['zhangDieFu'] = zhangDieFuitem['zhangDieE'] = zhangDieEitem['chengJiaoLiang'] = chengJiaoLiangitem['zhenFu'] = zhenFuitem['zuiGao'] = zuiGaoitem['zuiDi'] = zuiDiitem['jinKai'] = jinKaiitem['zuoShou'] = zuoShou# 使用 yield 语句将 item 传递到管道进行进一步处理yield item

step6:定义StockItem类

class StockItem(scrapy.Item):# Scrapy 的 Item 类用于定义数据结构,所有要提取的字段都在这里定义xuHao = scrapy.Field()  # 序号,表示股票在页面中的排列顺序guPiaoDaiMa = scrapy.Field()  # 股票代码,用于唯一标识每只股票guPiaoNingCheng = scrapy.Field()  # 股票名称,显示股票的名称zuiXingBaoJia = scrapy.Field()  # 最新报价,表示股票的当前价格zhangDieFu = scrapy.Field()  # 涨跌幅,显示股票价格变化的百分比zhangDieE = scrapy.Field()  # 涨跌额,表示股票价格上涨或下跌的金额chengJiaoLiang = scrapy.Field()  # 成交量,表示该股票在当前时段的交易量zhenFu = scrapy.Field()  # 振幅,表示股票价格波动的幅度zuiGao = scrapy.Field()  # 最高价,表示该股票在当前时段的最高交易价格zuiDi = scrapy.Field()  # 最低价,表示该股票在当前时段的最低交易价格jinKai = scrapy.Field()  # 今开,表示当天股票的开盘价zuoShou = scrapy.Field()  # 昨收,表示前一天股票的收盘价

step7:pipeline中,将数据存入mysql中

import mysql.connector  # 导入 MySQL 连接器,用于连接和操作数据库
from itemadapter import ItemAdapter  # 导入 Scrapy 的 ItemAdapter 类,方便操作爬取的 item 数据class StockPipeline:count = 0  # 计数器,用于跟踪数据处理的次数,确保只在第一次处理时创建数据库表def open_spider(self, spider):"""在爬虫启动时自动执行,负责连接数据库和创建表。- 连接 MySQL 数据库- 检查是否是第一次运行爬虫,如果是,则创建数据库表"""try:# 连接到 MySQL 数据库self.con = mysql.connector.connect(host="localhost",  # MySQL 数据库的主机地址user="root",  # MySQL 数据库的用户名password="123456",  # MySQL 数据库的密码database="DataAcquisition"  # 使用的数据库名)# 创建一个数据库游标,用于执行 SQL 语句self.cursor = self.con.cursor()# 如果是第一次运行爬虫(StockPipeline.count == 0),创建数据库表if StockPipeline.count == 0:try:# 如果已存在旧的表,删除它(避免表重复)self.cursor.execute("DROP TABLE IF EXISTS stock")# 创建一个新的表结构sql = """CREATE TABLE IF NOT EXISTS stock (xuHao VARCHAR(32) PRIMARY KEY,  # 股票编号,作为主键guPiaoDaiMa VARCHAR(32),  # 股票代码guPiaoNingCheng VARCHAR(32),  # 股票名称zuiXingBaoJia DECIMAL(10, 2),  # 最新报价,使用 DECIMAL 类型存储带小数的数值zhangDieFu VARCHAR(32),  # 涨跌幅zhangDieE DECIMAL(10, 2),  # 涨跌额,使用 DECIMAL 类型chengJiaoLiang INT,  # 成交量,使用 INT 类型zhenFu VARCHAR(32),  # 震幅zuiGao DECIMAL(10, 2),  # 最高价,使用 DECIMAL 类型zuiDi DECIMAL(10, 2),  # 最低价,使用 DECIMAL 类型jinKai DECIMAL(10, 2),  # 今开,使用 DECIMAL 类型zuoShou DECIMAL(10, 2)  # 昨收,使用 DECIMAL 类型)"""# 执行 SQL 语句创建表self.cursor.execute(sql)except Exception as e:# 如果表创建失败,记录错误信息spider.logger.error("Error creating table: %s", e)except Exception as err:# 如果数据库连接失败,记录错误信息spider.logger.error("Error connecting to MySQL: %s", err)def process_item(self, item, spider):"""处理每个爬取的 item,负责将数据插入数据库。- 从 item 中提取数据- 使用 SQL 插入数据到数据库"""try:# 准备插入数据的 SQL 语句sql = """INSERT INTO stock (xuHao, guPiaoDaiMa, guPiaoNingCheng, zuiXingBaoJia, zhangDieFu, zhangDieE, chengJiaoLiang, zhenFu, zuiGao, zuiDi, jinKai, zuoShou)VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""# 从 item 中提取字段值xuHao = item.get('xuHao', None)guPiaoDaiMa = item.get('guPiaoDaiMa', None)guPiaoNingCheng = item.get('guPiaoNingCheng', None)zuiXingBaoJia = item.get('zuiXingBaoJia', None)zhangDieFu = item.get('zhangDieFu', None)zhangDieE = item.get('zhangDieE', None)chengJiaoLiang = item.get('chengJiaoLiang', None)zhenFu = item.get('zhenFu', None)zuiGao = item.get('zuiGao', None)zuiDi = item.get('zuiDi', None)jinKai = item.get('jinKai', None)zuoShou = item.get('zuoShou', None)# 执行插入数据的 SQL 语句self.cursor.execute(sql, (xuHao, guPiaoDaiMa, guPiaoNingCheng, zuiXingBaoJia, zhangDieFu, zhangDieE,chengJiaoLiang, zhenFu, zuiGao, zuiDi, jinKai, zuoShou))# 提交事务,保存数据到数据库self.con.commit()except Exception as err:# 如果插入数据失败,记录错误信息spider.logger.error("Error inserting data: %s", err)# 返回 item,以便 Scrapy 继续处理return itemdef close_spider(self, spider):"""在爬虫结束时关闭数据库连接"""try:# 关闭数据库连接self.con.close()except Exception as err:# 如果关闭数据库连接时出错,记录错误信息spider.logger.error("Error closing MySQL connection: %s", err)

step8:运行代码

step9:得到结果

(二)心得

提升:做完后发现,好像还可以做一个翻页的数据抓取,但是没有时间做了,这个翻页是ajax请求的,后面有空可以再继续完善

本次股票数据爬取的难点主要是网页的动态数据抓取,选择好中间件,在middlewares.py中做相应的修改。在完成作业的过程中,逐渐掌握了 Scrapy 框架在处理动态网页数据时的基本操作。从请求 URL 的构造、页面解析到数据存储,每一步都需要仔细思考和调试。在 start_requests 方法中,针对不同页面的 URL 进行请求时,我深刻理解了动态请求构建的重要性,尤其是在涉及 JavaScript 渲染内容时,如何有效地获取页面数据。

在数据解析部分,遇到了许多由于 JavaScript 渲染导致的数据缺失问题,这使我意识到传统的 Scrapy 下载器无法满足需求,因此我引入了 Selenium 作为中间件来处理动态页面加载。这一步骤让我学会了如何结合 Selenium 和 Scrapy 来获取和处理动态网页,尤其是如何利用 implicitly_wait 确保页面完全加载。

parse 方法中,我进一步加深了对 XPath 的理解,能够灵活地从网页的复杂 HTML 结构中提取出准确的股票数据。定义 StockItem 类并将数据结构化,方便后续存储时的使用。在数据存储环节,通过使用 MySQL 连接器,我学会了如何将爬取的数据存储到数据库中,并在爬虫开始时创建表格结构,确保数据能够持久化保存。

整个项目让我深刻体会到数据爬取过程中的挑战,尤其是在面对动态网页时的技术细节。通过解决爬取过程中的空值处理、动态页面加载等问题,我积累了宝贵的经验,也加深了对爬虫技术的理解。

三、外汇网站数据爬取

码云仓库:作业3/task3 · 曹星才/2022级数据采集与融合技术 - 码云 - 开源中国

(一)步骤

step1:找到对应的网站页面,对不同页面的url进行处理

# start_requests 方法用于生成初始请求并发送到目标网站
def start_requests(self):pageNum = 2  # 设置要爬取的页数# 循环遍历页面,构造每个页面的 URLfor page in range(0, pageNum):if page == 0:# 第一页的 URL 结构不同,需要单独处理url = "https://www.boc.cn/sourcedb/whpj/index.html"else:# 其他页面的 URL 结构url = f"https://www.boc.cn/sourcedb/whpj/index_{page}.html"# 使用 scrapy.Request 发送请求,并指定回调函数 parse 来处理响应yield scrapy.Request(url=url, callback=self.parse)

step2:注意到网页中有空值,后面要进行相应的处理

step3:解析页面并提取数据

parse 方法解析网页响应并提取外汇牌价数据。首先将响应字节数据解码为 UTF-8 字符串,然后用 Scrapy 的 Selector 类解析 HTML 内容,定位到包含数据的表格。提取表格行,跳过表头,从第三行开始逐行遍历。对于每行,创建 ChinaBankItem 实例,使用 XPath 提取各列的数据:包括货币名称、现汇买入价、现钞买入价、现汇卖出价、现钞卖出价和更新时间,将其存入 item 对象。最终,通过 yielditem 传递到管道进行进一步处理。

# parse 方法用于解析页面响应并提取数据
def parse(self, response):data = response.body.decode('utf-8')  # 将响应的字节数据解码为 UTF-8 字符串# 使用 Scrapy 的 Selector 类解析解码后的 HTML 数据selector = scrapy.Selector(text=data)# 定位包含外汇牌价数据的表格,使用 XPath 表达式查找body = selector.xpath("//div[@class='publish']//table")# 提取表格中的所有行(<tr> 元素)trs = body.xpath(".//tr")# 提取表头信息(第二行),并打印表头内容用于调试info_th = trs[1].xpath('.//th/text()').extract()print(info_th)# 遍历所有行,从第三行开始(忽略表头),提取每行的数据for info in trs[2:]:item = ChinaBankItem()  # 创建一个 ChinaBankItem 实例,用于存储提取的数据# 使用 XPath 表达式提取每列的数据,并存储到 item 对应的字段中item["Currency"] = info.xpath("./td[1]/text()").get()  # 提取货币名称item["TBP"] = info.xpath("./td[2]/text()").get()  # 提取现汇买入价item["CBP"] = info.xpath("./td[3]/text()").get()  # 提取现钞买入价item["TSP"] = info.xpath("./td[4]/text()").get()  # 提取现汇卖出价item["CSP"] = info.xpath("./td[5]/text()").get()  # 提取现钞卖出价item["Time"] = info.xpath("./td[7]/text()").get()  # 提取更新时间# 将提取的数据传递到 item 管道(pipelines)进行处理yield item

注:如果直接使用.extract(),就没有办法获取空值,故这里采用get

step4:定义 ChinaBankItem 类

# 定义一个 ChinaBankItem 类,用于存储从网页中提取的数据
class ChinaBankItem(scrapy.Item):# 定义用于存储货币名称的字段Currency = scrapy.Field()# 定义用于存储“现汇买入价”的字段TBP = scrapy.Field()# 定义用于存储“现钞买入价”的字段CBP = scrapy.Field()# 定义用于存储“现汇卖出价”的字段TSP = scrapy.Field()# 定义用于存储“现钞卖出价”的字段CSP = scrapy.Field()# 定义用于存储“更新时间”的字段Time = scrapy.Field()

step5:mysql中创建数据库

step6:在mysql数据库创建bank表,并将爬取到的数据存储到表中

# 定义一个处理从 Scrapy 爬虫中提取数据的管道类
class ChinaBankPipeline:count = 0  # 定义一个类变量 count,用于跟踪处理的数据项数# 处理每个传入的 item 对象def process_item(self, item, spider):try:# 连接到 MySQL 数据库(请根据实际情况修改为你的数据库配置)con = mysql.connector.connect(host="localhost",  # 数据库主机地址user="root",  # 数据库用户名password="123456",  # 数据库密码database="DataAcquisition"  # 目标数据库名称)cursor = con.cursor()  # 创建一个游标对象,用于执行 SQL 语句# 如果这是第一个被处理的 item,则创建表结构if ChinaBankPipeline.count == 0:try:# 删除旧表(如果已存在)以避免冲突cursor.execute("DROP TABLE IF EXISTS bank")# 创建新的表结构sql = """CREATE TABLE IF NOT EXISTS bank (Currency VARCHAR(64) PRIMARY KEY,  # 货币信息,作为主键TBP FLOAT,  # 现汇买入价CBP FLOAT,  # 现钞买入价TSP FLOAT,  # 现汇卖出价CSP FLOAT,  # 现钞卖出价Time VARCHAR(64)  # 更新时间)"""cursor.execute(sql)  # 执行 SQL 语句创建表except Exception as e:print("Error creating table:", e)  # 如果出错,打印错误信息# 准备插入数据的 SQL 语句sql = """INSERT INTO bank (Currency, TBP, CBP, TSP, CSP, Time)VALUES (%s, %s, %s, %s, %s, %s)"""try:# 从 item 对象中提取数据currency = item.get('Currency')  # 获取货币信息tbp = item.get('TBP')  # 获取现汇买入价cbp = item.get('CBP')  # 获取现钞买入价tsp = item.get('TSP')  # 获取现汇卖出价csp = item.get('CSP')  # 获取现钞卖出价time = item.get('Time')  # 获取更新时间# 执行 SQL 插入语句,将数据插入数据库cursor.execute(sql, (currency, tbp, cbp, tsp, csp, time))except Exception as err:print("Error inserting data:", err)  # 如果插入数据时出错,打印错误信息# 提交事务,保存数据更改con.commit()# 关闭数据库连接con.close()except Exception as err:print("Error:", err)  # 如果连接数据库或其他操作失败,打印错误信息# 增加计数器,表示已处理的数据项数ChinaBankPipeline.count += 1# 返回处理后的 item 对象return item

step7scrapy crawl wea -s LOG_ENABLED=False运行项目

step8:mysql中查看结果

(二)心得

在完成这次外汇网站数据爬取的过程中,逐渐掌握了使用 Scrapy 框架获取网页数据的基本流程。从构造 URL 请求、解析网页到将数据存储在数据库中,每一步都需要细心和耐心。在 start_requests 方法中,处理不同页面的 URL 让我意识到构建动态请求的重要性。解析数据时,我注意到网页中可能会有空值,因此学习并应用了 .get() 方法来避免数据缺失问题,这显著提高了代码的稳定性和健壮性。

在提取数据的 parse 方法中,进一步加深了对 XPath 语法的理解,能高效地从复杂的 HTML 结构中定位和提取信息。定义 ChinaBankItem 类明确了数据结构,为后续的存储提供了便利。在存储数据环节,学会了使用 MySQL 连接和操作,理解了如何在管道中处理数据,创建表结构,并插入爬取的数据。

整个项目让我体会到数据爬取和处理的过程,项目中遇到的空值处理、数据库连接等问题,逐步慢慢的都解决了。

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

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

相关文章

Linux环境安装Splunk Enterprise服务端和Windows客户端Splunk Universal Forwarder

Ubuntu 22.04 安装Splunk Enterprise服务端这里采用安装Splunk Enterprise 8.2.5版本下载安装包 wget -O splunk-8.2.5-77015bc7a462-linux-2.6-amd64.deb https://download.splunk.com/products/splunk/releases/8.2.5/linux/splunk-8.2.5-77015bc7a462-linux-2.6-amd64.deb执…

数据采集第三次实践作业

第三次作业 作业①: 1.要求: 指定一个网站,爬取这个网站中的所有的所有图片,例如:中国气象网( http://www.weather.com.cn )。使用scrapy框架分别实现单线程和多线程的方式爬取。 –务必控制总页数(学号尾数2位)、总下载的图片数量(尾数后3位)等限制爬取的措施。输出…

WIN11 Chrome 双击打不开闪退及Chrome浏览器不能拖拽文件crx

WIN11 Chrome 双击打不开闪退及Chrome浏览器不能拖拽文件crx 1 WIN11 Chrome 双击打不开闪退 1.1 在 Windows 安全中心按照如下步骤操作1.2 右键对应的软件找到应用路径名称1.3 在程序设置按照如下图建立应用名称和后缀相同的命名,如 chrome.exe1.4 按照如下操作步骤打勾选项1…

LVM 使用与扩容总结

转载请注明出处:LVM(Logical Volume Manager,逻辑卷管理器)是一个用于Linux系统的磁盘管理工具。它提供了一种更加灵活的存储管理机制,可以方便地进行磁盘的扩容、缩减、快照以及迁移等操作。 基本概念物理卷(PV):物理磁盘或分区,如/dev/sda1。 卷组(VG):由一个或多…

针对搭建好的Self-Service-Password服务进行背景图片标题修改和去掉问答短信邮件功能选项的展示

官方链接https://ltb-project.org/documentation/index.html https://github.com/ltb-project/self-service-password关于安装我之前已经写了关于安装self-service-password相关的文章,具参考:https://www.cnblogs.com/autopwn/p/18208481修改背景先将要更改的背景图片上传上…

回归

回归时过境迁,上次发完博客后,之后的半年我努力学习,以106分的408分数极限通过了研究生考试初试,之后为了复试机试刷了ACWING,最终顺利通过了复试,被录取为硕士研究生。 进入新学校,技术上开始用java,springboot,mysql增删改查那一套;业务上一开始做开源仓的代码追溯…

开源 - Ideal库 -获取特殊时间扩展方法(四)

分享特殊时间获取的扩展方法,包括获取当前月第一个/最后一个指定星期几、上/下一个指定星期几、月份的第几周、年的第几周(ISO8601)、月份周数、是否周末、是否闰年、所在季度,提供详细代码和单元测试。书接上回,我们继续来分享一些关于特殊时间获取的常用扩展方法。01、获…

关于Windows外壳(Windows Shell)

在前面的文章中,我介绍过如何替换Windows Shell,将桌面替换为自己的程序。 但是这么做会有个问题,就是桌面环境未被初始化,即使创建了explorer.exe进程,桌面也不会出现。 这里搜集了一些关于WInlogon,LogonUI和Userinit的一些理论知识,有兴趣的小伙伴可以了解一下。Winlo…

如何修复 iPhone 无法通过 Quik App 的蓝牙连接来启动 GoPro Hero13 Black 的解决方案 All In One

如何修复 iPhone 无法通过 Quik App 的蓝牙连接来启动 GoPro Hero13 Black 的解决方案 All In One 最近再使用 GoPro Hero13 Black 的过程中发现 iPhone 经常无法通过 Quik App 的蓝牙唤起 GoPro 开机,需要手动删除 iPhone 的蓝牙匹配,并重新配对 GoPro, 非常麻烦和使用体验极…

VUE使用TS开发打包时发现校验问题无法打包

解决办法: 找到 tsconfig.app.json 这个文件,把他的include改为一个实际存在的空文件即可

企业博客在品牌建设中的作用

在数字营销时代,企业博客已成为品牌建设的重要工具。它不仅帮助企业与目标受众建立联系,还能够提升品牌形象、增强客户忠诚度,并推动销售。本文将探讨企业博客在品牌建设中的关键作用,并结合实际案例分析其效果。 一、建立品牌权威性 企业博客是展示行业知识和专业能力的平…