克服反爬虫机制爬取智联招聘网站
一、实验内容
1、爬取网站:
智联招聘网站(https://www.zhaopin.com/)
2、网站的反爬虫机制:
在我频繁爬取智联招聘网站之后,它会出现以下文字(尽管我已经控制了爬虫的爬取速度):
因此,我准备使用代理IP池爬取数据。网上多为付费的代理IP池,免费的IP池不稳定,因此我准备通过爬取有关代理IP池的网站上的IP地址搭建自己的代理IP池。
3、备注:
(1)通过分析智联招聘的AJAX接口,模拟AJAX请求直接获取json数据的方法爬取数据。
(2)如果两次请求的地址和参数相同,在不刷新页面的情况下,浏览器会缓存第一次请求的内容,服务端更新后浏览器仍然显示第一次的内容,这将会导致我们得不到最新的数据。因此我研究了智联招聘网站的url中的部分参数(下面会详细介绍)以使得我们爬取到的是最新数据,而不是浏览器中的缓存数据。
(3)当我们输入大于12的页数时,网站会自动修改为12。当我们浏览第12页时,可以看到“下一页”这个按钮变灰了。也就是说,智联招聘网站对于所有的搜索最多只显示12页的数据。这就导致我们得不到足够的数据量。因此我决定采用对多个关键字进行搜索来增加得到的数据量,当然这可能导致得到的数据冗余和重复,但是不管怎样我们都会对数据进行清洗(包括去重),所以这些重复的数据都会在去重中去掉。
二、实验步骤
1、分析智联招聘的AJAX接口
(1)找到数据所在的url
我使用的是谷歌浏览器。打开网页后,右击选择“检查”,再选择“Network”,我们可以浏览几页的内容,来观察页面出现了什么变化,如图出现了多个url:
观察我们可以看出,url有三种:
一种是page-title开头的,我们单击之后查看一下它的Preview,如图:
我们可以知道该url中是网页的标题、描述之类的信息,并没有我们需要的数据。
一种是user-city开头的,我们单击之后查看一下它的Preview,如图:
我们可以知道该url中主要是是用户的地址信息等,也没有我们需要的数据。
还有一种是sou?开头的,如图:
我们所需要的数据在这种url中。
(2)分析url的Headers
我们可以看到Request URL便是像这样拼接起来的。
我们来逐一分析一下各参数的含义:
经过分析,可以知道:
start: 90是指每一页开始的数据偏移量,start等于90说明是第二页,
pageSize: 90是指每一页的数据数,
cityId: 489是城市的编号,这里默认全国,
industry、workExperience、education、companyType、employmentType、jobWelfareTag、kt均为默认值,
kw是关键词,
_v和x-zp-page-request-id便是开篇提到的用以防止浏览器显示缓存数据的参数。
_v是一个随机的8位小数。
x-zp-page-request-id 由三部分组成,32位随机数据通过md5简单加密得到+ 当前时间戳 + 随机数6位。
在了解url各参数的含义之后,我们来分析一下Headers
这里的Host、Origin、Referer、User-Agent在以后会有用。
2、编写爬虫
(1)生成_v和x-zp-page-request-id
# 经过分析_v就是一个随机的8位小数
# x-zp-page-request-id 由三部分组成,32位随机数据通过md5简单加密得到+ 当前时间戳 + 随机数6位
# 想办法用python简单实现所谓的加密算法x-zp-page-request-id
# 1、生成一个随机32位数id
md5 = hashlib.md5()
id = str(random.random())
md5.update(id.encode('utf-8'))
random_id = md5.hexdigest()
# 2、生成当前时间戳
now_time = int(time.time() * 1000)
# 3、生成随机6位数
randomnumb = int(random.random() * 1000000)
# 组合代码生成x-zp-page-request-id
x_zp_page_request_id = str(random_id) + '-' + str(now_time) + '-' + str(randomnumb)
# print(x_zp_page_request_id)
# 生成_v
url_v = round(random.random(), 8)
# print(url_v)
(2)组成url发送请求,返回数据
get_page(start, key):两参数分别为起始偏移量和关键词。根据我们在1中的分析,将各参数放在params中,然后调用urlencode()函数将各参数拼接起来得到url,将该url传给download_retry()函数。
download_retry(url):接收一个url,调用requests.get()发送请求,如果返回来的结果状态码是200,说明服务器成功返回网页,接收数据并返回。
def get_page(start, key):params = {"start": str(start),"pageSize": "90","cityId": "489","industry": "160400",# "salary": str("0,0"),"workExperience": "-1","education": "-1","companyType": "-1","employmentType": "-1","jobWelfareTag": "-1","kw": key, # 关键词"kt": "3","at": "d47e5b2c03e74fa7afa8df838182f953","rt": "20618b2b78f748d795ea879f51221a4e",'_v': url_v,"userCode": "1029652508",'x-zp-page-request-id': x_zp_page_request_id}# print()url = "https://fe-api.zhaopin.com/c/i/sou?" + urlencode(params, encoding='GBK')newurl = url.replace("25", "")# print(url.replace("25", ""))# ajax请求头参数# 这里的headers是一个全局变量,在该函数内为headers赋值headers = {"Host": "fe-api.zhaopin.com","Origin": "https://sou.zhaopin.com","Referer": "https://sou.zhaopin.com/?jl=489&in=160400&sf=0&st=0&kw=" + key + "&kt=3","User-Agent": 'Baiduspider', # "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36","Accept-Encoding": "gzip, deflate, br"}result_json = download_retry(newurl)return result_jsondef download_retry(url):try:# 此时的数据库中的IP地址都是经过测试可用的# 从数据库中随机选择一个IP地址random_ip = 'SELECT proxy_type,ip, port FROM proxy_ip ORDER BY RAND() LIMIT 1;'cursor.execute(random_ip)proxy_type, ip, port = cursor.fetchone()proxies = {proxy_type: proxy_type + '://' + ip + ':' + port}requests.packages.urllib3.disable_warnings()response = requests.get(url, headers=headers, proxies=proxies, timeout=5)#result = json.loads(response.text)#print(result)if response.status_code == 200:result = response.json()else:result = Noneexcept:raise ConnectionErrorreturn result
(3)解析json数据,写入excel表格
def get_content(json):if json is not None:items = []result_items = json.get("data").get("results")#print(result_items)for item in result_items:dic = {}dic['job_name'] = item['jobName']dic['company_name'] = item['company']['name']dic['work_place'] = item['city']['display']dic['salary'] = item['salary']dic['education'] = item['eduLevel']['name']dic['experience'] = item['workingExp']['name']dic['welfare'] = item['welfare']dic['job_href'] = item['positionURL']dic['company_href'] = item.get("company").get("url")items.append(dic)# print(items)return itemsdef write_excel_xls_append(items):index = len(items) # 获取需要写入数据的行数workbook = xlrd.open_workbook("Job1.xls") # 打开工作簿sheets = workbook.sheet_names() # 获取工作簿中的所有表格worksheet = workbook.sheet_by_name(sheets[0]) # 获取工作簿中所有表格中的的第一个表格rows_old = worksheet.nrows # 获取表格中已存在的数据的行数new_workbook = copy(workbook) # 将xlrd对象拷贝转化为xlwt对象new_worksheet = new_workbook.get_sheet(0) # 获取转化后工作簿中的第一个表格for i in range(0, index):item = items[i]# 追加写入数据,注意是从i+rows_old行开始写入new_worksheet.write(i+rows_old, 0, item['job_name'])new_worksheet.write(i+rows_old, 1, item['company_name'])new_worksheet.write(i+rows_old, 2, item['work_place'])new_worksheet.write(i+rows_old, 3, item['salary'])new_worksheet.write(i+rows_old, 4, item['education'])new_worksheet.write(i+rows_old, 5, item['experience'])# str = ','.join(company_href[i]) # 用,将各福利连接起来new_worksheet.write(i+rows_old, 6, item['welfare'])new_worksheet.write(i+rows_old, 7, item['job_href'])new_worksheet.write(i+rows_old, 8, item['company_href'])new_workbook.save("Job1.xls") # 保存工作簿print("追加数据成功!")
(4)执行结果
执行程序后,用户可以无限输入关键词爬取数据,直到输入#表示程序退出。
在这里,我们输入“web”进行测试。(数据量大,只截图了开始和结束。)
此时的excel表格,我们可以看出数据已经追加成功。
3、建立代理IP池
(1)爬取西刺的免费IP代理保存到数据库中
获取当前的免费IP地址,端口,以及协议及速度。
import pymysql
import requests
from scrapy.selector import Selector# 数据库连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='web_crawler', charset='utf8')
cursor = conn.cursor()def crawl_ips():headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/59.0.3071.115 Safari/537.36"}for i in range(1, 1001):url = 'http://www.xicidaili.com/wt/{0}'.format(i)req = requests.get(url=url, headers=headers)selector = Selector(text=req.text)all_trs = selector.xpath('//*[@id="ip_list"]//tr') # 共同前缀ip_lists = []for tr in all_trs[1:]:speed_str = tr.xpath('td[7]/div/@title').extract()[0]if speed_str:speed = float(speed_str.split('秒')[0])ip = tr.xpath('td[2]/text()').extract()[0]port = tr.xpath('td[3]/text()').extract()[0]proxy_type = tr.xpath('td[6]/text()').extract()[0].lower()ip_lists.append((ip, port, speed, proxy_type))for ip_info in ip_lists:cursor.execute(f"INSERT proxy_ip(ip,port,speed,proxy_type) VALUES('{ip_info[0]}','{ip_info[1]}',{ip_info[2]},"f"'{ip_info[3]}') ")conn.commit()
#crawl_ips()
(2)从数据库中随机取免费的IP地址,并且判断该IP地址的可用性。
class GetIP(object):# 删除无效的免费ip信息def delete(self, ip):delete_sql = 'DELETE FROM proxy_ip WHERE ip="{0}"'.format(ip)cursor.execute(delete_sql)conn.commit()return Truedef valid_ip(self, ip, port, proxy_type):headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/59.0.3071.115 Safari/537.36"}try:proxies = {proxy_type: proxy_type + '://' + ip + ':' + port}req = requests.get('http://ip.chinaz.com/getip.aspx', headers=headers, proxies=proxies, timeout=5)except:print('invalid ip and port')self.delete(ip)return Falseelse:if 200 <= req.status_code < 300:# print('{0} effective ip~'.format(proxies))print(req.text)return Trueelse:print('invalid ip and port')self.delete(ip)return False# 随机从数据库中取ip地址@propertydef get_random_ip(self):random_ip = 'SELECT proxy_type,ip, port FROM proxy_ip ORDER BY RAND() LIMIT 1;'cursor.execute(random_ip)proxy_type, ip, port = cursor.fetchone()# 把获取到的ip地址通过拆包的方式分别复制给协议,IP以及端口,# 然后把这三个参数送给valid_ip方法做验证valid_ip = self.valid_ip(ip, port, proxy_type)if valid_ip:return {proxy_type: proxy_type + '://' + ip + ':' + port}else:return self.get_random_ipproxy = GetIP()
print(proxy.get_random_ip)
得到的IP地址(部分):
有人问全部的源码,其实上面就是所有的代码了,再加几个函数调用就行了。
def input_page_and_keyword():str = input("请输入关键词:(若停止输入,请输入#)")# print(type(str))while str != "#":write_excel_xls_append(crawler(12, str))input_page_and_keyword()if str == "#":print("程序退出。")input_page_and_keyword()
克服反爬虫机制爬取智联招聘网站相关推荐
- Scrapy学习——爬取智联招聘网站案例
Scrapy学习--爬取智联招聘网站案例 安装scrapy 下载 安装 准备 分析 代码 结果 安装scrapy 如果直接使用pip安装会在安装Twisted报错,所以我们需要手动安装. 下载 安装s ...
- (转)python爬虫实例——爬取智联招聘信息
受友人所托,写了一个爬取智联招聘信息的爬虫,与大家分享. 本文将介绍如何实现该爬虫. 目录 网页分析 实现代码分析 结果 总结 github代码地址 网页分析 以https://xiaoyuan.zh ...
- python爬虫实例——爬取智联招聘信息
受友人所托,写了一个爬取智联招聘信息的爬虫,与大家分享. 本文将介绍如何实现该爬虫. 目录 网页分析 实现代码分析 结果 总结 github代码地址 网页分析 以https://xiaoyuan.zh ...
- 爬取智联招聘网站的手段(scrapy)
首先www.zhaopin.com是智联招聘网站的首页,进行搜索后,比如搜Java,点右键查看网页源代码可以看到,网页里面搜到的内容是异步加载的如图所示: 然后点击f12打开开发者工具,如图: 再点击 ...
- scrapy框架下的两个爬虫分工合作爬取智联招聘所有职位信息。
爬虫一 本次爬取为两个爬虫,第一个爬虫爬取需要访问的URL并且存储到文本中,第二个爬虫读取第一个爬虫爬取的URl然后依次爬取该URL下内容,先运行第一个爬虫然后运行第二个爬虫即可完成爬取. 本帖仅供学 ...
- selenium+PyQuery+chrome headless 爬取智联招聘求职信息
最近导师让自己摸索摸索Python爬虫,好了就开始一发不可收拾的地步.正巧又碰到有位同学需要一些求职信息对求职信息进行数据分析,本着练练手的目的写了用Python爬取智联招聘网站的信息.这一爬取不得了 ...
- python 爬虫学习:抓取智联招聘网站职位信息(二)
在第一篇文章(python 爬虫学习:抓取智联招聘网站职位信息(一))中,我们介绍了爬取智联招聘网站上基于岗位关键字,及地区进行搜索的岗位信息,并对爬取到的岗位工资数据进行统计并生成直方图展示:同时进 ...
- 爬取智联招聘信息并存储
#-*- coding: utf-8 -*- import urllib.request import os,time from bs4 import BeautifulSoup #爬取智联招聘网站的 ...
- python爬虫多url_Python爬虫实战入门六:提高爬虫效率—并发爬取智联招聘
之前文章中所介绍的爬虫都是对单个URL进行解析和爬取,url数量少不费时,但是如果我们需要爬取的网页url有成千上万或者更多,那怎么办? 使用for循环对所有的url进行遍历访问? 嗯,想法很好,但是 ...
最新文章
- DNS 与 活动目录 的关系
- 手机端部署的超分机器学习模型-MobiSR
- POJ2369 置换群
- 推荐系统:MovivLens20M数据集解析
- ssl1746-商务旅行【tarjan,LCA】
- 力扣(LeetCode)292. Nim游戏 巴什博奕
- 归档和解档-Archiver
- pcie16x能插1x的卡嘛?_上高速后关掉ETC过龙门架,下高速再插上会更便宜吗?
- 好爽 java_JAVA Web学习(27)___第21章清爽夏日九宫格日记网
- 微信支付指纹要上传到服务器,华为即将支持微信指纹支付,同意上传至腾讯服务器!...
- GICv3软件overview手册之配置GIC
- 8月22日到26日工作收获
- 遥感的几何校正、正射校正、辐射校正
- java软件测试经典案例,java语言编程案例 - Mrsjjl的个人空间 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
- 【MATLAB】基本绘图 ( plot 函数绘制多个图形 | legend 函数标注图形 | 图形修饰 )
- 社会管理网格化 源码_张家口市召开市域社会治理暨全市网格化服务管理现场观摩会议...
- MAC M1 芯片在 yarn install 时报错:The CPU architecture “arm64“
- MyEclipse下载地址全攻略
- PX4 1.12版本后启用lpe导致飞控启动失败的问题的解决办法
- 一句shell命令搞定代码行数统计