多进程爬虫

[周更]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]))
       

总结

最后这个爬虫爬取的内容只有十几条,为什么这么少呢?是因为这个网站采用了动态加载的方法,我们只爬取了它初步加载的内容。这里如果想要爬取更多的内容就要用到异步加载的方法了。
ᕦ(・ㅂ・)ᕤ(任何不足之处,欢迎大家留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值