Python爬虫(7):多进程抓取拉钩网十万数据
由于拉钩网页面做了一些更新,之前的程序无法正常工作,本篇文章做一次更新。只更新一些程序和一些程序的实现方法。由于没有仔细修改,可能前后语言不通顺,大家谅解。
大家好,几天没有更新了。相信大家经过前两篇的练手爬虫,大家已经知道如何抓取一个简单网站。
这篇文章我们来抓取 拉钩网 的招聘信息。全部抓取大概十几万条全国招聘信息,并且保存数据库。
准备
安装Mongodb数据库
其实不是一定要使用MongoDB
,大家完全可以使用MySQL
或者Redis
,全看大家喜好。这篇文章我们的例子是Mongodb
,所以大家需要 下载 它。
在Windows
中。由于MongoDB
默认的数据目录为C:\data\db
,建议大家直接在安装的时候更改默认路径为C:\MongoDB
.
然后创建如下目录文件:
C:\data\log\mongod.log //用于存储数据库的日志 C:\data\db //用于存储数据库数据
然后在C:\MongoDB
文件夹下(安装 Mongodb 路径)创建配置文件mongod.cfg
。并且在配置文件里写入以下配置:
systemLog: destination: file path: C:\data\log\mongod.log storage: dbPath: C:\data\db
大家记住要打开文件后缀名,不然我们可能创建了一个mongod.cfg.txt
文件。
最后我们需要打开管理员权限的 CMD 窗口,执行如下命令,安装数据库成服务:
"C:\mongodb\bin\mongod.exe" --config "C:\mongodb\mongod.cfg" --install
设置为服务后,需要在管理员权限打开的windows cmd
窗口用服务的方式启动或停止MongoDB
。
net start mongodb //启动mongodb服务 net stop mongodb //关闭mongodb服务
好了,安装好Mongodb
数据库后,我们需要安装PyMongo
,它是MongoDB
的Python
接口开发包。
pip install pymongo
开始
准备完成后,我们就开始浏览拉勾网。我们可以发现拉勾网所有的招聘职位都在左侧分类里。如图:
我们先获取首页HTML文件:
import requests from bs4 import BeautifulSoup from requests.exceptions import RequestException url = 'https://www.lagou.com/' # 获取页面源码函数 def get_page_resp(url): headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'} try: resp = requests.get(url, headers=headers) if resp.status_code == 200: return resp.text return None except RequestException: return None soup = BeautifulSoup(get_page_resp(url), 'lxml')
然后我们打开开发者工具,找到招聘职业的位置。
大家还记得BeautifulSoup的CSS选择器吧,我们直接使用.select()
方法获取标签信息。
all_positions = soup.select('div.menu_sub.dn > dl > dd > a') print(all_positions) print(len(all_positions))
输出结果:
[<a class="curr" href="https://www.lagou.com/zhaopin/Java/" data-lg-tj-cid="idnull" data-lg-tj-id="4O00" data-lg-tj-no="0101">Java</a>, <a class="curr" href="https://www.lagou.com/zhaopin/C%2B%2B/" data-lg-tj-cid="idnull" data-lg-tj-id="4O00" data-lg-tj-no="0102">C++</a>, # ... 省略部分 <a class="" href="https://www.lagou.com/zhaopin/fengxiankongzhizongjian/" data-lg-tj-cid="idnull" data-lg-tj-id="4U00" data-lg-tj-no="0404">风控总监</a>, <a class="" href="https://www.lagou.com/zhaopin/zongcaifuzongcai/" data-lg-tj-cid="idnull" data-lg-tj-id="4U00" data-lg-tj-no="0405">副总裁</a>] 260
获取到所有职位标签的a
标签后,我们只需要提取标签的href
属性和标签内内容,就可以获得到职位的招聘链接和招聘职位的名称了。我们准备信息生成一个字典。方便我们后续程序的调用。
# 解析首页获得所有职位信息的函数 def parse_index(): url = 'https://www.lagou.com/' soup = BeautifulSoup(get_html(url), 'lxml') all_positions = soup.select('div.menu_sub.dn > dl > dd > a') joburls = [i['href'] for i in all_positions] jobnames = [i.get_text() for i in all_positions] for joburl, jobname in zip(joburls, jobnames): data = { 'url' : joburl, 'name' : jobname } # 这里使用yield语法糖,不熟悉的同学自己查看资料哦 yield data
这里我们用zip
函数,同时迭代两个list
。生成一个键值对。
接下来我们可以随意点击一个职位分类,分析招聘页面的信息。
分页
我们首先来分析下网站页数信息。经过我的观察,每个职位的招聘信息最多不超过 30 页。也就是说,我们只要从第 1 页循环到第 30 页,就可以得到所有招聘信息了。但是也可以看到有的职位招聘信息,页数并不到 30 页。以下图为例:
如果我们访问页面:https://www.lagou.com/zhaopin/Java/31/
也就是第 31 页。我们会得到 404 页面。所以我们需要在访问到404页面时进行过滤。
if resp.status_code == 404: pass
这样我们就可以放心的 30 页循环获得每一页招聘信息了。
我们的每一页url
使用format
拼接出来:
link = '{}{}/'.format(url, str(pages))
获取信息
我们可以看到上面划线的信息。这就是我们要抓取的信息了。
当然。抓取的方法千篇一律,我们可以使用find()
或find_all()
选择器,当然也可以使用 CSS选择器。但是 CSS选择器相对于前两者代码量稍微少一些。这里大家自己动手抓取,我们直接上代码供大家借鉴。
# 职位信息 positions = soup.select('ul > li > div.list_item_top > div.position > div.p_top > a > h3') # 工作地址 adds = soup.select('ul > li > div.list_item_top > div.position > div.p_top > a > span > em') # 发布时间 publishs = soup.select('ul > li > div.list_item_top > div.position > div.p_top > span') # 薪资信息 moneys = soup.select('ul > li > div.list_item_top > div.position > div.p_bot > div > span') # 工作需求 needs = soup.select('ul > li > div.list_item_top > div.position > div.p_bot > div') # 发布公司 companys = soup.select('ul > li > div.list_item_top > div.company > div.company_name > a') tags = [] # 由于我发现有的招聘信息没有标签信息,if判断防止没有标签报错 if soup.find('div', class_='li_b_l'): # 招聘信息标签 tags = soup.select('ul > li > div.list_item_bot > div.li_b_l') # 公司福利 fulis = soup.select('ul > li > div.list_item_bot > div.li_b_r')
获取到全部信息后,我们同样的把他们组成键值对字典。
for position,add,publish,money,need,company,tag,fuli in \ zip(positions,adds,publishs,moneys,needs,companys,tags,fulis): data = { 'position' : position.get_text(), 'add' : add.get_text(), 'publish' : publish.get_text(), 'money' : money.get_text(), 'need' : need.get_text().split('\n')[2], 'company' : company.get_text(), 'tag' : tag.get_text().replace('\n','-'), 'fuli' : fuli.get_text() }
组成字典的目的是方便我们将全部信息保存到数据库。
保存数据库
保存数据库前我们需要配置数据库信息:
import pymongo client = pymongo.MongoClient('localhost', 27017) lagou = client['lagou'] url_list = lagou['url_list']
这里我们导入了pymongo
库,并且与MongoDB
建立连接,这里是默认连接本地的MongoDB
数据。创建并选择一个数据库lagou
,并在这个数据库中,创建一个table
,即url_list
。然后,我们进行数据的保存:
if url_list.insert_one(data): print('保存数据库成功', data)
如果保存成功,打印出成功信息。
多进程抓取
十万多条数据是不是抓取的有点慢,有办法,我们使用多进程同时抓取。由于Python
的历史遗留问题,多线程在Python
中始终是个美丽的梦。
from multiprocessing import Pool def main(pages): datas = parse_index() for i in datas: url = i['url'] print(url) mongo_table = i['name'] # 因为有的职位是以'.'开头的,比如.Net,数据库表名不能以.开头 if mongo_table[0] == '.': mongo_table = mongo_table[1:] # 我们把之前抓取职位所有招聘信息的程序整理为parse_link()函数 # 这个函数接收职位url,页码,和数据库表名为参数 parse_link(url, pages, mongo_table)
我们把之前提取职位招聘信息的代码,写成一个函数,方便我们调用。这里的parse_link()
就是这个函数,他就收职位的 url 和所有页数为参数。我们get_alllink_data()
函数里面使用for
循环 30 页的数据。然后这个作为主函数传给多进程内部调用。
if __name__ == '__main__': pool = Pool(processes=6) pages = ([p for p in range(1, 31)]) pool.map(main,pages) pool.close() pool.join()
这里是一个pool
进程池,我们调用进程池的map
方法.
map(func, iterable[,chunksize=None])
多进程Pool
类中的map
方法,与Python
内置的map
函数用法行为基本一致。它会使进程阻塞,直到返回结果。需要注意,虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。join()
方法等待子进程结束后再继续往下运行,通常用于进程间的同步.
针对反爬
如果大家就这样整理完代码,直接就开始抓取的话。相信在抓取的不久后就会出现程序中止不走了。我刚刚第一次中止后,我以为是网站限制了我的 ip。于是我做了如下改动。
import random import time user_agent_list = [ 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', ' Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)' ] user_agent = random.choice(user_agent_list) headers = { 'User-Agent':user_agent, 'Connection':'keep-alive' } proxy_list = [ 'http://140.224.76.21:808', 'http://60.178.14.90:8081', 'http://121.232.146.13:9000', ] proxy_ip = random.choice(proxy_list) proxies = {'http': proxy_ip} resp = requests.get(url, headers=headers, proxies=proxies) time.sleep(1)
这里我是直接在在网上找了一些免费的ip
,还自己找了几个浏览器的user-agent
。利用Python
内置的random
库,开始随机选择列表里的user-agent
和ip
。并且将参数传入requests
内继续抓取。为了防止请求频率过快,我们设置每次请求结束停留一秒。然后我以为问题这么结束了。就开始继续抓取,但是在之前中断的位置突然有中断了。
于是,我在代码抓取信息位置添加了一句打印url
的代码。我得到了中断爬取的url
,然后我手动多点进去,发现了这个网页。当然出现这个情况并不是更换ip
不可以,而是我们的ip太少了,一个ip
可能仍然出现多次抓取的情况,后续我将会和大家一起写一个自己的ip
代理池。
模拟登录
没错这是一个登录界面,不知道是不是这里的浏览器头,或者ip请求过多。如果继续增多ip
和user_agent
就不会出现这种情况。
但是如何面对这种需要登录才能持续爬取的网站呢,很简单,我们只要打开浏览器的开发者工具。登录自己的账号,在Network
标签找一个请求,查看你的请求头部信息,找到自己的cookies
。这个cookies
就是你的登录信息了,我们需要将他和你的user-agent
一样,添加到请求头就可以了。如果大家不明白这个cookies
是什么,没关系,后面会有专门的讲解。
headers = { 'Cookie':'user_trace_token=20170603115043-d0c257a054ee44f99177a3540d44dda1; LGUID=20170603115044-d1e2b4d1-480f-11e7-96cf-525400f775ce; JSESSIONID=ABAAABAAAGHAABHAA8050BE2E1D33E6C2A80E370FE9167B; _gat=1; PRE_UTM=; PRE_HOST=; PRE_SITE=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; index_location_city=%E5%85%A8%E5%9B%BD; login=false; unick=""; _putrc=""; _ga=GA1.2.922290439.1496461627; X_HTTP_TOKEN=3876430f68ebc0ae0b8fac6c9f163d45; _ga=GA1.3.922290439.1496461627; LGSID=20170720174323-df1d6e50-6d2f-11e7-ac93-5254005c3644; LGRID=20170720174450-12fc5214-6d30-11e7-b32f-525400f775ce; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1500541369; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1500543655', 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', }
好了我们继续抓取,发现这次程序并没有中止。~~~但是由于博主网速过慢,抓取太慢了,还没有全部抓取下来,不知道后面会不会出现问题。~~~
这次更新,我是完全抓取玩全站才过来的,没错我已经抓取了全部的信息。用时1412 .9008133411407 秒。
好了,说了这么多,基本也都说完了。
项目地址
对整理代码有疑惑的伙伴可以点击 这里。
最后
这是我已经抓取的一部分。这里如果大家希望看到Mongodb
数据库里的保存内容。
我们需要安装一个Mongodb
可视化应用 robomango。
安装没什么要说的,大家链接到我们的lagou
数据库,就可以看到里面的数据了。
如果博主后面把全部数据抓下来后,可以和大家一起进行数据分析,分析Python
招聘的一些信息啊什么的。大家加油。
谢谢阅读
系列文章
- Python爬虫(1):基本原理
- Python爬虫(2):Requests的基本用法
- Python爬虫(3):Requests的高级用法
- Python爬虫(4):Beautiful Soup的常用方法
- Python爬虫(5):豆瓣读书练手爬虫
- Python爬虫(6):煎蛋网全站妹子图爬虫
- Python爬虫(7):多进程抓取拉钩网十万数据
- Python爬虫(8):分析Ajax请求爬取果壳网
- Python爬虫(9):Cookie介绍和模拟登录
- Python爬虫(10):Selenium+PhantomJS基本操作
- Python爬虫(11):Scrapy框架的安装和基本使用
- Python爬虫(12):Scrapy组件的用法
- Python爬虫(13):Scrapy实战抓取网易云音乐
原文地址:https://www.yukunweb.com/2017/6/python-spider-crawl-data-Multiprocess/
相关推荐
-
上海的房价有多贵?Python爬虫项目实战,为你做一个详细的分析 网络爬虫
2019-8-25
-
爬虫学习之一个简单的网络爬虫 网络爬虫
2018-2-26
-
超强cookie池发布,针对日趋严峻的反爬虫形势 网络爬虫
2019-2-24
-
Scrapy-Redis分布式抓取麦田二手房租房信息与数据分析 网络爬虫
2019-11-1
-
scrapy爬虫docker部署 网络爬虫
2019-2-21
-
爬虫攻防实践 网络爬虫
2019-7-20
-
通过网络图片小爬虫对比Python中单线程与多线(进)程的效率.txt 网络爬虫
2018-2-22
-
Python爬虫,抓取淘宝商品评论内容 网络爬虫
2019-8-25
-
一步一步教你 https 抓包 网络爬虫
2019-2-26
-
Python爬虫(12):Scrapy组件的用法 网络爬虫
2018-3-13