博客3

news/2025/11/23 16:30:03/文章来源:https://www.cnblogs.com/wosh/p/19260783

作业①:

要求:指定一个网站,爬取这个网站中的所有的所有图片,例如:中国气象网(http://www.weather.com.cn)。实现单线程和多线程的方式爬取。

通过解析htlm,找到所有<img>标签,爬取所有图片 。

完整代码:

import os
import re
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
from concurrent.futures import ThreadPoolExecutor, as_completed# ========== 配置 ==========
START_URL = "http://www.weather.com.cn"
SAVE_DIR = "images"
THREADS = 10os.makedirs(SAVE_DIR, exist_ok=True)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ""(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
def get_html(url):try:resp = requests.get(url, headers=headers, timeout=10)resp.encoding = resp.apparent_encodingreturn resp.textexcept Exception as e:print(f"[错误] 无法获取页面:{url},原因:{e}")return ""def get_image_urls(html, base_url):"""提取所有图片URL"""soup = BeautifulSoup(html, "html.parser")img_tags = soup.find_all("img")urls = set()for img in img_tags:src = img.get("src") or img.get("data-src")if src:full_url = urljoin(base_url, src)if re.match(r"^https?://", full_url):# 过滤非图片链接,仅保留常见格式if re.search(r"\.(jpg|jpeg|png|gif|webp|jpgs)(\?|$)", full_url, re.IGNORECASE):urls.add(full_url)return urlsdef get_extension_from_response(resp):"""根据Content-Type判断图片扩展名"""ctype = resp.headers.get("Content-Type", "").lower()if "png" in ctype:return ".png"elif "jpeg" in ctype:return ".jpg"elif "jpg" in ctype:return ".jpg"elif "gif" in ctype:return ".gif"elif "webp" in ctype:return ".webp"return ".jpg"def download_image(url):"""下载单张图片"""try:resp = requests.get(url, headers=headers, timeout=10)if resp.status_code == 200 and "image" in resp.headers.get("Content-Type", ""):filename = os.path.basename(urlparse(url).path)# 如果URL中没有后缀,则用Content-Type推断if not os.path.splitext(filename)[1]:filename += get_extension_from_response(resp)filepath = os.path.join(SAVE_DIR, filename)with open(filepath, "wb") as f:f.write(resp.content)print(f"[下载成功] {url}")else:print(f"[跳过] 非图片链接: {url}")except Exception as e:print(f"[失败] {url} 原因: {e}")# ========== 单线程 ==========
def single_thread_crawl(url):print("=== 单线程爬取开始 ===")html = get_html(url)img_urls = get_image_urls(html, url)print(f"共找到 {len(img_urls)} 张图片")for img_url in img_urls:print(f"[URL] {img_url}")download_image(img_url)print("=== 单线程爬取结束 ===")# ========== 多线程 ==========
def multi_thread_crawl(url):print("=== 多线程爬取开始 ===")html = get_html(url)img_urls = get_image_urls(html, url)print(f"共找到 {len(img_urls)} 张图片")with ThreadPoolExecutor(max_workers=THREADS) as executor:futures = [executor.submit(download_image, img_url) for img_url in img_urls]for _ in as_completed(futures):passprint("=== 多线程爬取结束 ===")# ========== 主入口 ==========
if __name__ == "__main__":print("请选择模式:")print("1. 单线程")print("2. 多线程")choice = input("输入1或2:").strip()if choice == "1":single_thread_crawl(START_URL)else:multi_thread_crawl(START_URL)

 

运行结果:

单线程:

多线程:

心得体会:
通过观察html发现所有图像都在标签<img>中,然后通过url进行下载,在单线程模式下,程序顺序地请求并保存每一张图片,逻辑清晰但效率较低;而在多线程模式中,我使用了 ThreadPoolExecutor 实现并发下载,使得多个图片可以同时被请求和保存,大幅提升了下载速度。通过比较两种模式的运行时间,我深刻体会到并行处理在网络 I/O 密集型任务中的显著优势。

作业②

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取股票相关信息。

通过抓包方式发现url中的page参数代表着页数,通过改变page参数于是实现了多页爬取。

完整代码:

import scrapy
import json
from scrapy_stock.items import StockItemclass SinaStockSpider(scrapy.Spider):name = "sinastock"# 起始页start_page = 1max_page = 5      def start_requests(self):url = f"https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/" \f"Market_Center.getHQNodeData?page={self.start_page}&num=40&sort=symbol&asc=1&node=sh_a&symbol=&_s_r_a=page"yield scrapy.Request(url=url, callback=self.parse, meta={'page': self.start_page})def parse(self, response):page = response.meta['page']try:data_list = json.loads(response.text)except:self.logger.error("JSON 解析失败")returnfor info in data_list:item = StockItem()item["bStockNo"] = info.get("symbol")item["bName"] = info.get("name")item["bPrice"] = info.get("trade")item["bUpDown"] = info.get("pricechange")item["bUpDownRate"] = info.get("changepercent")item["bVolume"] = info.get("volume")item["bAmount"] = info.get("amount")item["bAmplitude"] = info.get("amplitude")item["bHigh"] = info.get("high")item["bLow"] = info.get("low")item["bOpen"] = info.get("open")item["bClose"] = info.get("settlement")yield item# 翻页,递归爬取if page < self.max_page:next_page = page + 1next_url = f"https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/" \f"Market_Center.getHQNodeData?page={next_page}&num=40&sort=symbol&asc=1&node=sh_a&symbol=&_s_r_a=page"yield scrapy.Request(url=next_url, callback=self.parse, meta={'page': next_page})

 

运行结果:

心得体会:

本次实验让我深刻理解了 Scrapy 的数据流、Item 封装与 Pipeline 处理,掌握了 Xpath 数据提取 和 MySQL 持久化 的完整流程,同时提升了对爬虫项目结构化、模块化设计的认识。

作业③:

要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。

候选网站:中国银行网:https://www.boc.cn/sourcedb/whpj/

通过观察可以发现,所有数据都在<tbody>里面

完整代码:

import scrapy
from scrapy_forex.items import ForexItemclass BocSpider(scrapy.Spider):name = "boc"allowed_domains = ["boc.cn"]start_urls = ["https://www.boc.cn/sourcedb/whpj/"]def parse(self, response):# 直接抓 table 下所有 tr,然后跳过表头rows = response.xpath("//table/tr")[1:]  # 第一行是表头 <tr class="odd">for row in rows:tds = row.xpath("./td/text()").getall()tds = [td.strip() for td in tds if td.strip()]if len(tds) < 8:continueitem = ForexItem()item['currency'] = tds[0]item['tbp'] = self.safe(tds[1])item['cbp'] = self.safe(tds[2])item['tsp'] = self.safe(tds[3])item['csp'] = self.safe(tds[4])item['avg'] = self.safe(tds[5])item['date'] = tds[6]item['time'] = tds[7]yield itemdef safe(self, value):"""空值或 '--' 转为 None"""try:return float(value)except:return None

 

运行结果:


心得体会:
本次实验任务是使用 Scrapy 框架爬取中国银行外汇牌价信息,并将数据通过 Item 封装后,利用 Pipeline 写入 MySQL 数据库,同时实现序列化输出。实验过程中,我首先定义了 ForexItem,字段包括货币名称、现汇买入价、现钞买入价、现汇卖出价、现钞卖出价、中行折算价、发布日期和时间。通过 Xpath 精准定位 <table> 中的 <tr> 和 <td> 节点,实现数据提取。实验初期遇到的问题主要是数据抓取不到。原因在于网页结构复杂,tbody 上层的 table 标签未正确定位。通过本次实验,我掌握了 Scrapy 数据流的完整流程:Spider 抓取、Item 封装、Pipeline 清洗存储,同时加深了对 Xpath 定位和数据库操作的理解,提高了爬虫的稳健性和可用性。

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

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

相关文章

语音频谱特征提取(python)

注:FFT(快速傅里叶变换);DFT(离散傅里叶变换);DCT(离散余弦变换);VMD(变分模态分解) 音频文件读取: import torchaudio def open_audio(audio_file): # Load an audio file.sig, sr = torchaudio.load(a…

深入解析:flink实验三:实时数据流处理(踩坑记录)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

触觉感知机器人如何规划与执行动作

本文详细介绍了一种新型机器人系统如何通过触觉传感技术实现复杂操作。系统配备六维力传感器和专用末端工具,能够在受限空间中进行物品抓取和存放,结合计算机视觉与深度学习算法实现精确的运动规划和控制。触觉感知机…

2025 年 11 月江苏省骨科医院权威推荐榜:专科诊疗、医保定点、工伤定点,专业骨科服务与高效医疗保障之选

2025 年 11 月江苏省骨科医院权威推荐榜:专科诊疗、医保定点、工伤定点,专业骨科服务与高效医疗保障之选 骨科疾病作为常见病和多发病,已成为影响人民群众生活质量的重要因素。随着人口老龄化进程加快和运动损伤增多…

2025 年 11 月智能配电系统厂家权威推荐榜:配电柜/配电箱/开关柜源头工厂,高效节能与稳定安全技术深度解析

2025 年 11 月智能配电系统厂家权威推荐榜:配电柜/配电箱/开关柜源头工厂,高效节能与稳定安全技术深度解析 随着工业4.0和智能电网建设的深入推进,智能配电系统作为电力能源管理的核心环节,正迎来技术革新与产业升…

iptables下MySQL安全防护怎么做

在使用iptables进行MySQL安全防护时,主要目标是限制不必要的网络访问,只允许特定的IP地址或IP段访问MySQL服务器,并禁用root用户的远程登录。以下是一些具体的步骤和建议:允许特定IP地址或IP段访问MySQL:使用ipta…

iptables下MySQL安全设置有哪些

在使用iptables进行MySQL安全设置时,主要目标是限制不必要的网络访问,保护数据库服务器免受潜在攻击。以下是一些建议的安全设置:默认拒绝所有外部访问:在iptables中,首先设置默认策略为拒绝所有外部对MySQL端口的…

2025 年 11 月防水公司权威推荐榜:商铺装修防水、别墅补漏防水、厂房防潮防水,专业施工与持久防护口碑之选

2025 年 11 月防水公司权威推荐榜:商铺装修防水、别墅补漏防水、厂房防潮防水,专业施工与持久防护口碑之选 防水工程作为建筑领域的关键环节,直接影响建筑物的使用寿命与安全性能。随着建筑行业对防水标准要求的不断…

SHOW STATUS LIKE Aborted_connects; 这个连接是啥意思

Aborted_connects 是 MySQL 全局状态计数器之一,表示“服务器端统计到的失败或被中止的连接尝试次数”。它不是当前连接数,而是一个累计次数(自上次服务器启动或自执行 FLUSH STATUS 起重新累计),用来衡量有多少次…

2025 年 11 月无锡公考/考编培训机构权威推荐榜:事业单位与央企国企招录培训实力解析及口碑优选指南

2025 年 11 月无锡公考/考编培训机构权威推荐榜:事业单位与央企国企招录培训实力解析及口碑优选指南 行业背景与发展趋势 近年来,随着公务员、事业单位及央企国企招录制度的不断完善,公职类考试培训行业呈现出专业化…

人工智能之编程进阶 Python高级:第十一章 过渡项目

人工智能之编程进阶 Python高级:第十一章 过渡项目人工智能之编程进阶 Python高级 第十一章 过渡项目以下是 ​5 个由浅入深、覆盖 Python 核心技能的实战项目​,每个项目都包含:🎯 项目目标 🔧 技术栈(知识点…

CF2122

CF2122D Traffic Lights 如果只有第一问的话,每个点分 \(\operatorname{deg}\) 个点跑分层图即可,但是在第二问这个就很没有道理了,因为是可以通过来回走来节省等待时间的。 所以每个点必须分成 \(t\) 个点。那么我…

《d2l Chapter4 多层感知机基础内容》

通俗细节讲解多层感知机基础原理,以及实际运用,并附有Latex数学公式与细节代码实现Chapter 4 : 多层感知机(MLP)先看看这个原理简单的嵌套式的“双层”的线性回归 \[\mathbf{X} \in \mathbb{R}^{n \times d} \]表示…

洛谷P2678题解

P2678虽然是黄题,但是只要想通思路,就会变得异常简单。 以下是思路《跳石头》算法思路详解.url100分错1个点代码:点击查看代码 #include<bits/stdc++.h> using namespace std; int L,N,M,d[50005]; bool chec…

【JVM】详解 Class类文件的结构 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实验3_CPP

任务1 源代码 button.hpp #pragma once#include <iostream> #include <string>class Button { public:Button(const std::string &label_);const std::string& get_label() const;void click();pr…

longchain4j 学习系列(4)-mcp调用

继续学习langchain4j,以下是langchain4j 调用MCP的示例: 1、添加pom依赖1 <dependency> 2 <groupId>dev.langchain4j</groupId> 3 <artifactId>langchain4j-mcp</artifactId>…

Java 学习路线可按「基础→进阶→实战→架构」四阶段推进

一、基础入门阶段(1-2个月) 核心目标:掌握Java语法和基本编程思维,能独立写简单程序。 核心知识点: 环境搭建(JDK安装、IDEA使用、环境变量配置) 基础语法(变量、数据类型、运算符、流程控制、数组) 面向对象…

Jetson Orin Nano super -2 烧录概念及必要性

一、什么是烧录?(核心定义) 烧录(又称 “写入”“刷写”)是指 将预先打包好的系统镜像、程序固件或驱动文件,通过专用工具和协议,写入嵌入式设备(如 Jetson 开发板、单片机)的存储介质(如 eMMC、SD 卡、NVMe…

blog搬迁

博客已经搬迁到https://langx1ng.github.io/处我要吃炸鸡