Python爬虫实战入门六:提高爬虫效率—并发爬取智联招聘

提高爬虫效率—多进程并发

之前文章中所介绍的爬虫都是对单个URL进行解析和爬取,url数量少不费时,但是如果我们需要爬取的网页url有成千上万或者更多,那怎么办? 使用for循环对所有的url进行遍历访问? 嗯,想法很好,但是如果url过多,爬取完所有的数据会不会太过于耗时了? 对此我们可以使用并发来对URL进行访问以爬取数据。 一般而言,在单机上我们使用三种并发方式:

  • 多线程(threading)
  • 多进程(multiprocessing)
  • 协程(gevent)

对于以上三种方法的具体概念解释和说明,各位可以自行网上搜索了解,相信会比我解释得清楚,所以在此就不对它们进行解释说明了。 本系列文章有两个重点,一个是实战,一个是入门,既为实战,理论性的东西就描述得比较少;既为入门,所讲述的都是简单易懂易操作的东西,高深的技术还请入门之后自行探索,那样也会成长得更快。 那么下面,开始并发爬取的实战入门,以多进程为例,并发爬取智联招聘的招聘信息。

一、分析URL和页面结构

1、搜索全国范围内职位名包含“Python”的职位招聘 我们不分职业类别、不分行业类别,工作地点选为全国,职位名为“Python”,对招聘信息进行搜索,结果如下图:

我们注意图中三个红框的信息:

  1. 搜索结果的url结构;(构造url地址进行for循环遍历)
  2. 搜索结果的条数;(判断url的数量)
  3. 采集的信息的主体;(解析数据)

通过筛选url参数,我们确定了需要爬取的基本URL为:

http://sou.zhaopin.com/jobs/searchresult.ashx?jl=全国&kw=python&kt=3&p=2

其中

http://sou.zhaopin.com/jobs/searchresult.ashx为请求地址和目录

jl:工作地点参数 kw:搜索的关键字 kt:以职位名搜索 p:页数

我们可以发现,除了页数会变化之外,其余的参数值都是固定的值。我们来确定一下搜索结果的总页数。 因为网页上有提示一共有多少个职位满足条件,我们拿总职位数除以单页显示的职位数量即可知道搜索结果的页数。

# coding:utf-8
import requests
from bs4 import BeautifulSoup
import re

url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?jl=全国&kw=python&p=1&kt=3'wbdata = requests.get(url).content
soup = BeautifulSoup(wbdata, 'lxml')

items = soup.select("div#newlist_list_content_table > table")
count = len(items) - 1# 每页职位信息数量print(count)

job_count = re.findall(r"共<em>(.*?)</em>个职位满足条件", str(soup))[0]# 搜索结果页数pages = (int(job_count) // count) + 1print(pages)

结果返回每页60条职位信息,一共有14页。 那么我们的待爬取的url地址就有14个,url地址中参数p的值分别从1到14,这么少的url,使用for循环也可以很快完成,但在此我们使用多进程进行演示。

二、在爬虫中使用多进程

先上代码:

# coding:utf-8
import requests
from bs4 import BeautifulSoup
from multiprocessing import Pool
def get_zhaopin(page):
    url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?jl=全国&kw=python&p={0}&kt=3'.format(page)
    print("第{0}页".format(page))
    wbdata = requests.get(url).content
    soup = BeautifulSoup(wbdata,'lxml')

    job_name = soup.select("table.newlist > tr > td.zwmc > div > a")
    salarys = soup.select("table.newlist > tr > td.zwyx")
    locations = soup.select("table.newlist > tr > td.gzdd")
    times = soup.select("table.newlist > tr > td.gxsj > span")    for name, salary, location, time in zip(job_name, salarys, locations, times):
        data = {            'name': name.get_text(),            'salary': salary.get_text(),            'location': location.get_text(),            'time': time.get_text(),
        }
        print(data)
if __name__ == '__main__':
    pool = Pool(processes=2)
    pool.map_async(get_zhaopin,range(1,pages+1))
    pool.close()
    pool.join()

结果如下:

因为除了使用了多进程之外,其他的代码与之前文章介绍的方法大同小异,所以在此只介绍一下多进程的核心代码:

from multiprocessing import Pool

multiprocessing是Python自带的一个多进程模块,在此我们使用其Pool方法。

if __name__ == '__main__':
    pool = Pool(processes=2)
    pool.map_async(get_zhaopin,range(1,pages+1))
    pool.close()
    pool.join()
  1. 实例化一个进程池,设置进程为2;
  2. 调用进程池的map_async()方法,接收一个函数(爬虫函数)和一个列表(url列表)

如此,在爬虫中使用多进程进行并发爬取就搞定了,更多高级、复杂强大的方法,还请各位参考其他文档资料。

原文发布于微信公众号 - 州的先生(zmister2016)

原文发表时间:2017-01-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏听雨堂

读书笔记:基于web的工作流引擎设计

1、工作流引擎以工作流管理联盟的XPDL(XML Process Definition Language)语言为过程定义语言。 2、基于B/S结构的工作流系统...

2739
来自专栏Golang语言社区

游戏服务端究竟解决了什么问题?

当讨论到游戏服务端的时候,我们首先想到的会是什么?要回答这个问题,我们需要从游戏服务端的需求起源说起。

1072
来自专栏企鹅号快讯

前后端分离实践

前后端分离并不是什么新鲜事,到处都是前后端分离的实践。然而一些历史项目在从一体化 Web 设计转向前后端分离的架构时,仍然不可避免的会遇到各种各样的问题。由于层...

3308
来自专栏IT米粉

MQ(消息队列)常见的应用场景解析

提高系统性能首先考虑的是数据库的优化,之前一篇文章《数据库的使用你可能忽略了这些》中有提到过开发中,针对数据库需要注意的事项。但是数据库因为历史原因,横向扩展是...

1052
来自专栏悦思悦读

码农的瑞士军刀-脚本语言

首先声明,这里关于语言间的比较仅仅是为了说明问题。世界上没有一个开发语言有绝对的好坏,只有是否适合你当前的环境。 很多码农工作的非常辛苦,每天加班。一般情况,团...

36410
来自专栏Java架构

Java程序员如何运用所掌握的技术构建一个完整的业务架构

1455
来自专栏老九学堂

这是篇Java数据库开发的干货,你确定不收藏吗?

无论你开发的是一款PC端的Web应用,还是一款移动端的app,都需要一个数据库来存储你的业务数据(包括电商的商品信息、游戏的道具信息、社交的人员信息等等)。可以...

3325
来自专栏Python数据科学

Python爬虫之工作篇—寻找你的招聘信息

最近总被智联招聘广发骚扰,烦死个人了简直。索性点进去看了看爬虫工程师现在市场需求到底怎么样了?发展前景如何?看完了之后感觉目前还不错,根据北京来看职位需求还是蛮...

901
来自专栏python开发者

软件开发过程自动化原理及技术(完整示例)

软件开发过程自动化原理及技术 一个简单完整的自动化示例 1   概述 关于本文,最开始只是想写一些关于 软件自动化测试开发 的文章,但是后来写着写着,发现不先在...

1985
来自专栏Youngxj

全民k歌解析工具

1674

扫码关注云+社区