背景目标
一个爬虫程序,默认情况下,是单线程爬取的,速度会比较慢
如果改造成多线程爬取,就可以利用多CPU能力,加速爬取。
如下代码,爬取了一个小说的内容,存储到文件里。
import requests
from bs4 import BeautifulSoup
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
root_url = "http://antpython.net/novels/01.html"
resp_root = requests.get(root_url, headers=headers)
soup = BeautifulSoup(resp_root.text, "html.parser")
chapter_links = soup.find("div", id="novel_chapters").find_all("div", class_="chapter_link")
import time
start = time.time()
# file out
fout = open("小说.txt", "w", encoding="utf8")
count = len(chapter_links)
for idx, chapter_link in enumerate(chapter_links):
link = chapter_link.find("a")
href = "http://antpython.net%s" % link["href"]
title = link.get_text()
print("爬取链接:", href, title, idx, count, idx / count * 100)
resp_cont = requests.get(href, headers=headers)
soup_cont = BeautifulSoup(resp_cont.text, "html.parser")
cont = soup_cont.find("div", id="chapter_content").get_text()
fout.write(title + "\n")
fout.write(cont + "\n")
fout.close()
print("爬取时间:", time.time() - start)
执行后,看到花费时间为爬取时间:56.08秒钟。
代码改造
需要注意的是,如果是并发爬取,那么爬取的顺序是不一致的。我们可以给每次URL给一个序号,将来做排序。
首先,将每章爬取改造成函数
def craw_single(index, title, chapter_link):
"""爬取单章内容,返回需要、标题、内容"""
resp_cont = requests.get(chapter_link, headers=headers)
soup_cont = BeautifulSoup(resp_cont.text, "html.parser")
cont = soup_cont.find("div", id="chapter_content").get_text()
return index, title, cont
其中index参数,纯粹是为了将来的排序使用。
然后,启动每章的爬取,提交给线程池
import time
start = time.time()
count = len(chapter_links)
pool = ThreadPoolExecutor()
futures = []
for idx, chapter_link in enumerate(chapter_links):
link = chapter_link.find("a")
href = "http://antpython.net%s" % link["href"]
title = link.get_text()
futures.append(pool.submit(craw_single, index=idx, title=title, chapter_link=href))
我们使用pool.submit做任务的提交,然后用futures收集future的结果对象。
等待所有线程的结束
results = []
for future in concurrent.futures.as_completed(futures):
results.append(future.result())
该代码会挨个等待子线程的结束。将结果future.result(),也就是函数的返回数据,存入列表中
将结果存入文件
results.sort(key=lambda x: x[0])
with open("小说结果.txt", "w", encoding="utf8") as fout:
for index, title, cont in results:
fout.write(title + "\n")
fout.write(cont + "\n")
pool.shutdown()
print("爬取时间:", time.time() - start)
这里对数据做了排序,按章节的顺序。
然后打开文件写入内容。
最后关闭了线程池。
总结
要把任务改造成多线程,先把要拆分的任务改成单个函数。然后用线程池做任务提交。都提交后,可以等待获取任务的返回。对返回数据做处理后,写出到文件里。
以下是我整理的一些提升程序员自身能力的资料,都已经整理并打包好了。
-END-
关于Python技术储备
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
一、Python学习路线
二、Python基础学习
1. 开发工具
给大家准备考Python开发过程中需要用到的必备工具,包括最新版PyCharm安装永久激活工具。
2. 学习笔记
3. 学习视频
三、Python小白必备手册
四、Python实战案例
五、Python爬虫秘笈
六、数据分析全套资源
七、Python面试集锦
1. 简历模板
资料领取
这份完整版的Python全套学习资料已为大家备好,朋友们如果需要可以微信扫描下方二维码添加,输入"领取资料" 可免费领取全套资料【有什么需要协作的还可以随时联系我】朋友圈也会不定时的更新最前言python知识。↓↓↓
或者
【点此链接】领取