周六. 7 月 19th, 2025

?点击“博文视点Broadview”,获取更多书讯

你是否有这样的问题,学 Python 语言之后,能做什么?

Python的用途其实非常多,今天先来展示一个用Python采集漫画信息的实操案例。

01

目标站点数据源分析

爬去目标

本次要爬取的网站是一个漫画网站,打开站点,呈现在我们面前的是 15660 部漫画信息,我们的目标是全部“拿下”。

为了降低学习难度,本文只介绍针对列表页进行抓取的过程,里面涉及的目标数据结构如下。

1. 漫画标题

2. 漫画评分

3. 漫画详情页链接

4. 作者

同时,在案例代码中需要同步保存漫画封面,并以封面文件名为漫画命名。

漫画详情页还存在大量的标签,因不涉及数据分析,故不再提取。

涉及的Python模块

爬取模块requests,数据提取模块re,多线程模块 threading。

重点学习内容

爬虫编写流程。

数据提取,重点掌握行内 CSS 提取。

CSV 格式文件存储。

变换IP 规避反爬,该目标网站有反爬机制。

列表页分析

通过点击测试,得到的页码变化逻辑如下。

https://vol.moe/l/all,all,all,sortpoint,all,all,BL/1.htm

https://vol.moe/l/all,all,all,sortpoint,all,all,BL/2.htm

https://vol.moe/l/all,all,all,sortpoint,all,all,BL/524.htm

页面数据是服务器直接静态返回的,加载到 HTML 页面中。

目标数据所在的 HTML DOM 结构如下所示。

在正式编写代码前,可以先有针对性地处理一下正则表达式部分。

匹配封面图

在编写该部分正则表达式时,出现了下图所示的“折行+括号”问题。

正则表达式如下,这里重点需要注意 \s 可匹配换行符。

<div[.\s]*style=”background:url\((.*?)\)

匹配文章标题、作者、详情页地址

该部分内容所在的 DOM 行格式比较特殊,可以直接匹配出结果。下述正则表达式使用了分组命名的方法。

<a href=(?P<url>.*?)>(?P<title>.*?)</a> <br /> (?P<author>.*?) <br />

对于动漫评分部分的匹配就非常简单了,直接编写如下正则表达式即可。

<p style=“.*?”><b>(.*?)</b></p>02

整理出的需求

整理需求如下。 

1. 开启 5 个线程对数据进行爬取。

2. 保存所有的网页源码。

3. 依次读取源码,提取元素到 CSV 文件中。

本案例将优先保存网页源码到本地,然后对本地 HTML 文件进行处理。

03

编码时间

在编码测试的过程中,我们发现该网站存在反爬措施,会直接封杀爬虫程序的IP,导致程序还没有跑起来,就结束了。

再次测试,发现反爬技术使用重定向操作,即服务器发现是爬虫后,直接返回状态码 302,并重定向谷歌网站。

IP受限制的时间大概是 24 个小时,因此如果希望爬取到全部数据,需要通过不断切换 IP 和 UA ,将 HTML 静态文件保存到本地。

下述代码可以判断目标网站返回的状态码,如果为 302,则更换代理 IP,再次爬取。

import requestsimport reimport threadingimport timeimport random# 以下为UA列表,为节省篇幅只保留两项,完整版请联系作者获取USER_AGENTS = [ “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)”, “Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)”,]# 循环获取 URLdef get_image(base_url, index): headers = { “User-Agent”: random.choice(USER_AGENTS) } print(f”正在抓取{index}) try: res = requests.get(url=base_url, headers=headers, allow_redirects=False, timeout=10) print(res.status_code) # 当服务器返回 302状态码之后 while res.status_code == 302: # 可直接访问 http://118.24.52.95:5010/get/ 获得一个代理IP ip_json = requests.get(“http://118.24.52.95:5010/get/”, headers=headers).json() ip = ip_json[“proxy”] proxies = { “http”: ip, “https”: ip } print(proxies) # 使用代理IP继续爬取 res = requests.get(url=base_url, headers=headers, proxies=proxies, allow_redirects=False, timeout=10) time.sleep(5) print(res.status_code) else: html = res.text # 读取成功,保存为 html 文件 with open(f”html/{index}.html”, “w+”, encoding=“utf-8”) as f: f.write(html) semaphore.release() except Exception as e: print(e) print(“睡眠 10s,再去抓取”) time.sleep(10) get_image(base_url, index)if __name__ == __main__: num = 0 # 最多开启5个线程 semaphore = threading.BoundedSemaphore(5) lst_record_threads = [] for index in range(1, 525): semaphore.acquire() t = threading.Thread(target=get_image, args=( f”https://vol.moe/l/all,all,all,sortpoint,all,all,BL/{index}.htm”, index)) t.start() lst_record_threads.append(t) for rt in lst_record_threads: rt.join()

只开启了 5 个线程,爬取过程如下所示。

经过 20 多分钟的等待,524 页数据全部以静态页形式保存在了本地 HTML 文件夹中。

 

当文件全部存储到本地之后,再进行数据提取就非常简单了。编写如下提取代码,使用 os 模块。

import osimport reimport requestsdef reade_html(): path = r”E:\pythonProject\test\html” # 读取文件 files = os.listdir(path) for file in files: # 拼接完整路径 file_path = os.path.join(path, file) with open(file_path, “r”, encoding=“utf-8”) as f: html = f.read() # 正则提取图片 img_pattern = re.compile(<div[.\s]*style=”background:url\((.*?)\)) # 正则提取标题 title_pattern = re.compile(“<a href=(?P<url>.*?)>(?P<title>.*?)</a> <br /> \[(?P<author>.*?)\] <br />”) # 正则提取得到 score_pattern = re.compile(<p style=”.*?”><b>(.*?)</b></p>) img_urls = img_pattern.findall(html) details = title_pattern.findall(html) scores = score_pattern.findall(html) # save(details, scores) for index, url in enumerate(img_urls): save_img(details[index][1], url)# 数据保存成 csv 文件def save(details, scores): for index, detail in enumerate(details): my_str = “%s,%s,%s,%s\n” % (detail[1].replace(“,”, “,”), detail[0], detail[2].replace(“,”, “,”), scores[index]) with open(“./comic.csv”, “a+”, encoding=“utf-8”) as f: f.write(my_str)# 图片按照动漫标题命名def save_img(title, url): print(f”正在抓取{title}{url}) headers = { “User-Agent”: “Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52” } try: res = requests.get(url, headers=headers, allow_redirects=False, timeout=10) data = res.content with open(f”imgs/{title}.jpg”, “wb+”) as f: f.write(data) except Exception as e: print(e)if __name__ == __main__:reade_html()

代码提取到 csv 文件如下所示。

关于详情页,即动漫的更新信息,可以使用上述逻辑再次爬取。

04

总结

完全学会本文中的操作,不仅需要用到 Python 的基础知识,还要掌握Python requests 模块、正则模块 re 、文件读写、多线程模块的相关内容。

想要快速学习这些内容,可以从阅读《滚雪球学Python》这本书开始。

滚雪球学 Python,书如其名,教授大家用类似滚雪球的思维学习 Python,第一遍浏览 Python 核心内容,第二遍补齐周边知识,第三遍夯实,第四遍拔高。每一遍滚雪球式的学习,都能丰富自己的知识。

限时五折优惠,快快扫码抢购吧!

发布:刘恩惠

审核:陈歆懿

如果喜欢本文欢迎 在看留言分享至朋友圈 三连<  PAST · 往期回顾  >Python,30年上位之路! 点击阅读原文,查看本书详情!

Avatar photo

作者 UU 13723417500

友情提示:现在网络诈骗很多,做跨境电商小心被骗。此号发布内容皆为转载自其它媒体或企业宣传文章,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。---无意冒犯,如有侵权请联系13723417500删除!

声明本文由该作者发布,如有侵权请联系删除。内容不代表本平台立场!

发表回复

服务平台
跨境人脉通
选品平台
U选Market
展会&沙龙
群通天下