python成功爬取拉勾网(一个小白的心里路程)
最开始想爬取拉钩是因为半年前上python实验课的时候,老师给了两个任务,一个时爬取糗百的笑话内容,另一个时爬取拉勾网的职位信息,当时因为课时紧张的缘故,老师讲解了关于爬虫的相关的库(requests,BeautifulSoup库等)的基本使用方法,发下了爬取糗百网的源码,让我们自己试一试,说是拉勾网不好爬取,目前的水平不够。疫情在家这几天我基本可以容易的爬取静态网页相关的内容,便想的试试爬取拉钩。
先观察网页源码:
很容易从源码看出所有相关的信息都放在li标签的属当中,具体的工资值放在span标签当中
我用直接用原来爬取静态网页的方法直接爬取:
import bs4
import requests
import re
from bs4 import BeautifulSoup
url = 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
try:
hd = {'user-agent': 'chorme/10'}
r = requests.get(url, headers=hd)
r.raise_for_status()
r.encoding = r.apparent_encoding
text = r.text
#print(text)
except:
print("")
soup = BeautifulSoup(text,'html.parser')
#print(soup.prettify())
'''
salary = re.findall(r'<span class="money">(.*?)</span>',str(text),re.S)
print(salary)
'''
for i in soup.find_all('li',attrs={'class':'con_list_item first_row default_list'}):
print(i)
代码中很容易看出,我用正则表达式对span标签进行查找,可是有返回的结果,但并不是自己想要的结果,后用soup.findall方式尝试对li标签直接进行查找,但却返回的是空的结果,但之前输出返回的网页源码内容均存在,我想不通是为什么。。。
一开始我认为是正则表达式出错,但检查过后并不是这样的错误,我便上网查找大佬们已经成功的案例,发现大佬代码中的headers内容不仅仅只是伪装的了发起请求的浏览器,而且还带了许多我没有见到的方法属性值,我也更换了相同的头部进行了再次尝试。。。
try:
hd = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
r = requests.get(url, headers=hd)
r.raise_for_status()
r.encoding = r.apparent_encoding
text = r.text
#print(text)
except:
print("")
出现了这样的错误
到这里开始我便知道不能轻易的爬取拉钩,我便开始了解拉钩的反爬机制。
常见的反爬虫策略
请求头校验
这应该是最常见最容易解决的反爬虫。python的库自动生成的请求头的’user-agent’里常常带有python这样的关键字,网站一看就发现并不是正常的用户访问,直接拒绝请求。有些网站还会注意请求头里的’referer’这样的属性,所以在构建爬虫的时候,伪装请求头是必须的,尤其是’user-agent’这一项。
cookie校验
有些网站会检验访问的时候携带的cookie,如果是直接向某个指定url发起连接而没有携带上一级网页的cookie,就会拒绝你的访问。
IP校验和设备ID校验
检查访问的IP地址已经是反爬虫的常见手段。当某一个IP频繁访问就会激活网站的反爬虫机制,所以IP池的建立和维护也是爬虫工程师的必修功课。每一个设备都有一个唯一的device-id,部分网站会通过检查频繁访问的设备ID进行反爬虫,当遇到了这样的网站的时候,做设备ID的伪装也是必要的。
通过网页动态加载提高爬取门槛
静态网站一个简单的请求就能拿到所有信息,动态网页加载会让爬虫工程师花更多的精力在网页的分析上。当然,任何网站都是能爬的,只是简单和困难的区别而已。 通过登陆提高爬取门槛很多网站会把信息隐藏起来,只对登陆用户可见,同时大部分网站都会有验证码,以大名鼎鼎的12306的验证码最为著名。同时和登陆一起做反爬虫的还有登陆元素的动态生成,所以熟练的做模拟登录和cookie池的维护也是必须会使用的技能。
这是我查找的反爬资料,拉钩网本身属于动态页面,请求信息返回在json数据格式当中,而且在模拟请求访问的时候,头部信息中不带本页面的cookies信息也无法正确返回所要的内容,其反爬方式囊括可上述所有的基本反爬机制。
按我自己的理解来解析反爬(模仿大佬们的路程加自己的理解)
使用谷歌浏览器来搜索拉勾网,用f12来查看器其网页请求信息等。(只能是谷歌浏览器)
在Network -> XHR -> Headers 中记录了所有头部的信息,包括url链接,data内容,请求方式,cookies等所有相关的内容,可以用这些东西去拼接更加完整的请求头部。
这里附上一个关于谷歌network详解的链接,因为是一位csdn大佬缩写,很详细。
network详解
在Network -> XHR -> Preview中可以找到请求返回的信息,是josn格式
所以在爬取信息处理时我们可以采用json数据格式来处理数据。在查阅大佬们完成的代码中,可以得出,要想正确的获取请求信息,关键在于cookies,因为拉钩网的反爬机制在设置时头部信息中必须包含本页面所带的cookies信息,需要获取搜索结果那一页的cookie 以及header里面需要添加Accept、Referer、User-Agent。
在对cookise的信息处理时,requests库的session会话对象可以跨请求保持某些参数,说白了,就是比如你使用session成功的登录了某个网站,则在再次使用该session对象求求该网站的其他网页都会默认使用该session之前使用的cookie等参数
尤其是在保持登陆状态时运用的最多,在某些网站抓取,或者app抓取时,有的时强制登陆,有的是不登陆返回的数据就是假的或者说是不完整的数据,那我们不可能去做到每一次请求都要去登陆一下怎么办,就需要用到保持会话的功能了,我们可以只登陆一次,然后保持这种状态去做其他的或者更多的请求。
在了解了整个后,直接上整个源代码:
import requests
import json
import time
url_request = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false' #network -> headers中显示的请求链接
url_html = 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=' #网页显示访问链接
hd = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
'''
爬取多页职位信息
for i in range(1,6):
data = {
'first': 'true',
'pn': 'str(i)',
'kd': 'python'
}
'''
#根据network -> headers显示的data来设置data
data = {
'first': 'true',
'pn': '1',
'kd': 'python'
}
# 创建一个session对象
s = requests.Session()
#发送请求,获得cookies
s.get(url_html,headers = hd,data = data,timeout = 4)
cookie = s.cookies
response = s.post(url_request,data = data,headers = hd,cookies = cookie,timeout = 4) #获得此次文本
#print(response)
response.encoding = response.apparent_encoding
time.sleep(6)
#response.encoding = response.apparent_encoding
#print(response.text)
text = json.loads(response.text)
#print(text)
info = text["content"]["positionResult"]["result"]
for i in info:
#print(i)
print(i["companyFullName"])
companyFullName = i["companyFullName"]
print(i["positionName"])
positionName = i["positionName"]
print(i["salary"])
salary = i["salary"]
print(i["companySize"])
companySize = i["companySize"]
print(i["skillLables"])
skillLables = i["skillLables"]
print(i["createTime"])
createTime = i["createTime"]
print(i["district"])
district = i["district"]
print(i["stationname"])
stationname = i["stationname"]
print("-------------------------")
运行后的结果:
我自己需要学习的还有很多,还年轻,努力!
。
来源:CSDN
作者:cici_vivi
链接:https://blog.csdn.net/zc666ying/article/details/104297483