[周更]2.多进程
继续周更ε≡٩(๑>₃<)۶ 一心向学
文章目录
声明
本内容为个人学习笔记,不准被用于商业。
前言
以并发的方式执行的爬虫速度要显著优于单线程爬虫。Python实现并发的方式有许多种,包括多线程,多进程,还有多协程。但多线程和多协程都并没有真正意义上发挥多核CPU的优势。所以在本篇短文中,我们主要介绍多进程方法。
一、多进程
multiprocessing.Pool常用函数:
- apply_async(func[, args]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表;
- apply(func[, args[, kwds]]):使用阻塞方式调用func
- close():关闭Pool,使其不再接受新的任务;
- join():主进程阻塞,等待子进程的退出, 必须在close之后使用;
在本文中使用非租塞方法,加快爬取速度。
二、使用步骤
1.引入库requests,re,os,multiprocessing
代码如下:
import requests #用来请求内容
import re #正则表达式库
import os #用来打开文件夹来储存图片
import time #引入是为了减慢爬取速度
from multiprocessing import Pool, Manager #多进程所需
2.初始化(注意设置header)
就将header设置为成下面这个样子即可。
代码如下:
start_directory = r'E:\Python\requests模块\texts'
#储存新闻的位置(**可以修改**)
os.startfile(start_directory)
#调用os,将这个位置设置为储存位置
url = r""
#要爬取的主网页,我们要爬取新闻的网址全部在这上面
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0',
}
response = requests.get(url=url,headers = headers)
#这是要爬取网址的基本样式
add_urls = re.findall(r'(?<=href=")https:\/\/w{3}\.jiemian\.com\/article\/\d*?\.html(?=")', response.text)
add_urls = list(set(add_urls))
#去除重复元素,add_urls储存着所有要爬取的网址
3.创建进程池
manager = Manager()
#manager这里可以共享列表,字典等很多数据类型
#其本身与多进程关系不大
workQueue = manager.Queue(1000)
#创建一个最大任务数为1000的队列
for url in add_urls:
workQueue.put(url)
#将网址放入队列中
pool = Pool(processes=3)
for i in range(3):
pool.apply_async(crawler,args=(workQueue,i))
#分别将进程池这三个进程挂上队列
print('Start!')
pool.close()
pool.join()
#开始爬取
4.创建爬取的函数
我们要将一个函数输入进程池中。
def crawler(q,index):
#第一个参数即队列,第二个参数即处理器的序号
Process_id = 'Process-' + str(index)
while not q.empty():
#当序列不为空时,提取其中的一个元素
url = q.get(timeout=2)
try:
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0',}
response = requests.get(url=url,headers = headers)
title = re.findall(r'(?<=<h1>).*?(?=</h1>)', response.text)
content_main = re.findall(r'(?<=<p>).*?(?=</p>)', response.text)
#正则表达式!!
content_str =''
#因为最后我想把新闻内容连为一个字符串,所以创建一个空字符创
for content in content_main:
content_str+=content
content_str = re.sub(r'', ' ', content_str)
content_str = re.sub(r'<a.*?>', ' ', content_str)
content_str = re.sub(r'<span.*?</span>', ' ', content_str)
#继续正则!尽量优化,去除无关内容
with open(r'E:\Python\requests模块\texts\{}.txt'.format(title[0]),'wb') as w:
w.write(content_str.encode('utf-8'))
#将爬取内容写入文件中,记得一定要转为utf-8编码
print("{}: {}标题的新闻爬取成功".format(Process_id,title[0]))
except Exception as e:
print(e)
5.将爬内容的函数加载入进程池中
其实就是上文中的
for i in range(3):
pool.apply_async(crawler,args=(workQueue,i))
#分别将进程池这三个进程挂上队列
pool.close()
#表示不可再插入元素
pool.join()
#主进程阻塞等待子进程的退出
6.完整代码
多进程版:
import requests
import re
import os
import time
from multiprocessing import Pool, Manager
def crawler(q,index):
#第一个参数即队列,第二个参数即处理器的序号
Process_id = 'Process-' + str(index)
while not q.empty():
#当序列不为空时,提取其中的一个元素
url = q.get(timeout=2)
try:
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0',}
response = requests.get(url=url,headers = headers)
title = re.findall(r'(?<=<h1>).*?(?=</h1>)', response.text)
content_main = re.findall(r'(?<=<p>).*?(?=</p>)', response.text)
#正则表达式!!
content_str =''
#因为最后我想把新闻内容连为一个字符串,所以创建一个空字符创
for content in content_main:
content_str+=content
content_str = re.sub(r'', ' ', content_str)
content_str = re.sub(r'<a.*?>', ' ', content_str)
content_str = re.sub(r'<span.*?</span>', ' ', content_str)
#尽量优化,去除无关内容
with open(r'E:\Python\requests模块\texts\{}.txt'.format(title[0]),'wb') as w:
w.write(content_str.encode('utf-8'))
#将爬取内容写入文件中,记得一定要转为utf-8编码
print("{}: {}标题的新闻爬取成功".format(Process_id,title[0]))
except Exception as e:
print(e)
if __name__=="__main__":
start_directory = r'E:\Python\requests模块\texts'
#储存新闻的位置(**可以修改**)
os.startfile(start_directory)
#调用os,将这个位置设置为储存位置
url = r"https://www.jiemian.com/lists/35.html"
#要爬取的主网页,我们要爬取新闻的网址全部在这上面
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0',
}
response = requests.get(url=url,headers = headers)
#https://www.jiemian.com/article/7162690.html
#这是要爬取网址的基本样式
add_urls = re.findall(r'(?<=href=")https:\/\/w{3}\.jiemian\.com\/article\/\d*?\.html(?=")', response.text)
add_urls = list(set(add_urls))
#去除重复元素,add_urls储存着所有要爬取的网址
manager = Manager()
workQueue = manager.Queue(1000)
#创建一个最大任务数为1000的队列
for url in add_urls:
workQueue.put(url)
#将网址放入队列中
pool = Pool(processes=3)
#创建具有三个处理器的进程池
for i in range(3):
pool.apply_async(crawler,args=(workQueue,i))
#分别将进程池这三个进程挂上队列
print('Start!')
pool.close()
#表示不可再插入元素
pool.join()
#主进程阻塞等待子进程的退出
#开始爬取
无多进程版:
import requests
import re
import os
import time
if __name__=="__main__":
start_directory = r'E:\Python\requests模块\texts'
os.startfile(start_directory)
url = r"https://www.jiemian.com/lists/35.html"
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0',
}
response = requests.get(url=url,headers = headers)
#print(response.text)
with open("News_Theme.html",'w') as f:
f.write(response.text)
#https://www.jiemian.com/article/7162690.html
add_urls = re.findall(r'(?<=href=")https:\/\/w{3}\.jiemian\.com\/article\/\d*?\.html(?=")', response.text)
add_urls = list(set(add_urls)) #去除重复元素
titles = []
contents = []
for url in add_urls:
time.sleep(1)
response = requests.get(url=url,headers = headers)
title = re.findall(r'(?<=<h1>).*?(?=</h1>)', response.text)
titles.append(title[0])
content_main = re.findall(r'(?<=<p>).*?(?=</p>)', response.text)
content_str =''
for content in content_main:
content_str+=content
content_str = re.sub(r'', ' ', content_str)
content_str = re.sub(r'<a.*?>', ' ', content_str)
content_str = re.sub(r'<span.*?</span>', ' ', content_str)
#print(content_str)
contents.append(content_str)
with open(r'E:\Python\requests模块\texts\{}.txt'.format(title[0]),'wb') as w:
w.write(content_str.encode('utf-8'))
print("{}标题的新闻爬取成功".format(title[0]))
总结
最后这个爬虫爬取的内容只有十几条,为什么这么少呢?是因为这个网站采用了动态加载的方法,我们只爬取了它初步加载的内容。这里如果想要爬取更多的内容就要用到异步加载的方法了。
ᕦ(・ㅂ・)ᕤ(任何不足之处,欢迎大家留言)