Python学习之多进程并发爬虫

以前做过Python的爬虫,不过那只爬取贴吧内容,比较简单,只是用来刚开始练练手的。这段时间又重新看Python,看到了正则表达式,于是想对爬虫再深入的了解下,主要是对爬虫的线程以及进程学习。


爬虫是io密集型,所以使用多线程会提高效率,但是懂点Python的人都知道,gil的存在导致Python的多线程有点坑,这里简单的介绍下gil。
Gil 是全局解释器锁,为了数据的安全。而在Python的多线程下,每个线程的执行方式为:

  • 获取Gil
  • 执行代码知道sleep或者是Python虚拟机将其挂起
  • 释放Gil

从这里可以看得出来线程要想执行,必须要拿到Gil,但是在一个Python中只有一个Gil,而每次释放Gil锁,线程进行锁竞争、切换线程,会消耗资源,并且一个进程永远只能同时执行一个线程(拿到Gil的线程才能执行),所以Python中的多线程效率并不高。所以想要了解的话可以看下这篇博客多线程验证学习下。


下面来说下多进程的爬虫,Python中使用多进程需要multiprocessing,以及提供了process、queue、pipe、lock、pool等组件,这里主要使用的是pool,可以叫做进程池,想要了解其他的组件可以看下这篇博客http://cuiqingcai.com/3335.html


使用pool先了解下:

  • pool = Pool(n) #建立进程池,n就是代表了建立几个进程,这个n的设定一般与cpu的核数一样
  • pool.map(def,list)#把列表list里面的每一项映射到你所定义的def函数内,有点通过这句话做list各项循环的意味
  • pool.close()#关闭进程池,不再接受新的进程
  • pool.join()#主进程阻塞等待子进程安全退出,父子进程同步

    多进程爬虫实例:

这里以爬取猫眼电影中的top100电影为例子。

import json
from multiprocessing import Pool
import requests
from requests.exceptions import RequestException
import re

def get_one_page(url): #判断页面的请求状态来做异常处理
    try:
        response = requests.get(url)
        if response.status_code == 200:#200是请求成功
            return response.text
        return None
    except RequestException:
        return None

def parse_one_page(html):
    pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?<p class="name">.*?data-val.*?>(.*?)</a>'#正则表达式
                         +'.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
                         +'.*?integer">(.*?)</i>.*?fraction">(\d+)</i>.*?</dd>',re.S)
    items = re.findall(pattern, html) #返回正则结果
    for item in items:  #对结果进行迭代,修饰
        yield{
            '排名:':item[0],
            '电影:':item[1],
            '主演:':item[2].strip()[3:],
            '上映时间:':item[3].strip()[5:],
            '评分:':item[4]+item[5]
        }
def write_to_file(content): #写入文件“result.txt”中
    with open('result.txt', 'a', encoding='utf-8') as f: #以utf-8的编码写入
        f.write(json.dumps(content, ensure_ascii=False) + "\n") #json序列化默认使用ascii编码,这里禁用ascii
        f.close()

def main(page):
    url = "http://maoyan.com/board/4?offset=" + str(page) #page 为页码数
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        write_to_file(item)

if __name__ == '__main__':
    '''
    for i in range(10):
        main(i*10)
    '''
    pool = Pool() #建立进程池
    pool.map(main, (i*10 for i in range(10)))#映射到主函数中进行循环

在使用多进程的时候还可以加入异步,这个还没有学习,之后会加入进来,在爬取大量的数据时候或者图片的时候会大大的提高效率。


在学习Python的爬虫可以到这上面去学习:

虫师
静觅

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值