想吃石锅鱼,我现在还没吃上饭。。。。
拉勾网我想爬好久了,但是苦于不会分析ajax,搁了挺久,现在学会了,终于可以如愿所偿了。
虽然说爬虫已经完成了,但还是有很多不足,比如,只能爬取120条信息,也就是9页,之后我的ip就会被封掉。
下面几点问题:
-
我研究了一会,我发现我的cookies会一直变,如果一段时间间不更新cookise,就会无法访问,弹出访问太频繁的页面。
-
如果短时间内获取多页,就会被封ip
第一点我可以利用requests来更新cookies,但是现在还不会;第二点可以利用代理池解决但是我现在也不。这就是为什么我要把这个分开来写的原因。
先来看看我现在能够做到哪一步:
利用到的库:
import requests
import json
from pymongo import MongoClient
from multiprocessing import Pool
from urllib.parse import urlencode
import time
一定要安装数据库,并且打开服务,我用的mongodb(真好用),你们用别的也行。
我看了看拉勾网的robots.txt文件,如下:
User-agent: Jobuispider
Disallow: /
User-agent: *
Disallow: /resume/
Disallow: /nearBy/
Disallow: /ologin/
Disallow: /jobs/list_*
Disallow: /one.lagou.com
Disallow: /ns3.lagou.com
Disallow: /hr.lagou.com
Disallow: /two.lagou.com
Disallow: /t/temp1/
Disallow: /center/preview.html
Disallow: /center/previewApp.html
Disallow: /*?utm_source=*
Allow: /gongsi/interviewExperiences.html?companyId=*
Disallow: /*?*
我需要的信息在这里:https://www.lagou.com/jobs/list_*
emmmm.....所以,就在刚才,我还是爬了,于是我被封了,这就导致了我现在无法访问。
然后,我们打开拉勾网主页,并搜索‘python’:
image.png过滤器选‘应届生、本科生’。就可以看到这样的界面:
image.png我们按F12进入开发者模式:
点击network->XHR——》刷新页面,就可以看到。。。。。。。。。。
对不起,我啥都看不到了,只能看到让我登录的页面。。。。
你们应该能看到有4条记录,然后我们点击第二页,又会出来四条,经过观察我们要的信息在pos*开头的ajax请求的一条,点preview就可看到返回的响应了。
我看到请求的url没变,而且方式是post,就来了兴趣,昨天的是get方法。
headers向下拉,可以看到form信息,和请求参数,
这是我之前保存的:
params:
'xl': '本科',
'px': 'default',
'gx': '全职',
'needAddtionalResult': 'false',
'isSchoolJob': '1'
form:
'first': 'false',
'kd': 'python',
'pn': 2
一个小时后我补上的
观察后发现,第一页的first为true,第二页以后都为false,pn就是页码,所以我们就可以根据此来的到每一页的代码了。
这里注意请求头信息一定要是最新的,不然只能吃灰,就是那个cookies。
于是我就写出了如此完美的请求函数:
def get_one_page(pagenum):
'''
pagemun为页数,获取一页的信息
:param pagenum:
:return json:
'''
params = {
'xl': '本科',
'px': 'default',
'gx': '全职',
'needAddtionalResult': 'false',
'isSchoolJob': '1'
}
data = {
'first': 'false' if pagenum != 1 else 'true',
'kd': 'python',
'pn': pagenum
}
headers = {
'Host': 'www.lagou.com',
'Connection': 'keep-alive',
'Content-Length': '26',
'Origin': 'https://www.lagou.com',
'X-Anit-Forge-Code': '0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest',
'X-Anit-Forge-Token': 'None',
'Referer': 'https://www.lagou.com/jobs/list_python?px=default&gx=%E5%85%A8%E8%81%8C&gj=&xl=%E6%9C%AC%E7%A7%91&isSchoolJob=1&city=%E5%85%A8%E5%9B%BD',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cookie': 'WEBTJ-ID=20190328100105-169c2078019103-03287e499e7cc-7a1437-1327104-169c207801a0; _ga=GA1.2.1664461408.1553738469; _gid=GA1.2.1954202981.1553738469; user_trace_token=20190328100111-5bf04f0f-50fd-11e9-b40b-525400f775ce; LGUID=20190328100111-5bf053d7-50fd-11e9-b40b-525400f775ce; JSESSIONID=ABAAABAAADEAAFI9211681F55FF42AB9EE85C8EC6C94593; index_location_city=%E5%85%A8%E5%9B%BD; TG-TRACK-CODE=index_search; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22169c40de3e43ad-0357531209afde-7a1437-1327104-169c40de3e524d%22%2C%22%24device_id%22%3A%22169c40de3e43ad-0357531209afde-7a1437-1327104-169c40de3e524d%22%7D; sajssdk_2015_cross_new_user=1; _gat=1; LGSID=20190328201212-b7f050c6-5152-11e9-b9c8-525400f775ce; PRE_UTM=; PRE_HOST=www.baidu.com; PRE_SITE=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DKbms6xfMqIUv7AMjnRPDL-xkTFJ6snHQGL9DF5fQumm%26wd%3D%26eqid%3De29fa16f0000d8bc000000035c9ca96a; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; SEARCH_ID=2798721a148d4f538908ca0bd396d4ac; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1553771063,1553775087,1553775136,1553775450; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1553775450; LGRID=20190328201727-7371eef8-5153-11e9-b831-5254005c3644'
}
base_url = "https://www.lagou.com/jobs/positionAjax.json?"
url = base_url+urlencode(params)
try:
response = requests.post(url, headers=headers, data=data)
print('页面获取成功')
if response.status_code == 200:
# print(response.json())
return response.json()
except requests.ConnectionError as e:
print("error", e.args)
return None
接下来解析数据:
image.png响应是 json 格式,非常有结构。
我们要找到我们要的信息在哪里,然后提取我们需要的,我为了以后方便数据分析,我保存了不少信息。
非常清晰明了。
def parse_page(json):
'''
解析收到的信息
:param json:
:return dict:
'''
items = json.get('content').get('positionResult').get('result')
if items:
for item in items:
try:
# job
positionName = item.get('positionName')
positionLables = item.get('positionLables')
salary = item.get('salary')
jobNature = item.get('jobNature')
education = item.get('education')
# company
city = item.get('city')
district = item.get('district')
companyShortName = item.get('companyShortName')
industryField = item.get('industryField')
financeStage = item.get('financ eStage')
companyId = item.get('companyId')
companyLabelList = item.get('companyLabelList')
companySize = item.get('companySize')
except:
pass
else:
yield {
# job
'positionName': positionName,
'positionLables': positionLables,
'salary': salary,
'jobNature': jobNature,
'education': education,
# company
'city': city,
'district': district,
'companyShortName': companyShortName,
'industryField': industryField,
'financeStage': financeStage,
'companyId': companyId,
'companyLabelList': companyLabelList,
'companySize': companySize,
}
(简书编辑器怎么会出红线啊,我又没写错,真闹心)
得到了信息就是保存了,这跟昨天的是一样的,保存到mongodb数据库:
def save_to_db(item, collection):
'''
保存数据导数据库
:param item:
:param collection:
:return:
'''
result = collection.insert_one(item)
print(result)
然后是main函数,链接数据库,衔接函数:
def main(pagenum):
'''
主函数,输入页码
:param pagenum:
:return:
'''
# 链接数据库并选择集合
print('开始第{0}'.format(pagenum))
client = MongoClient('mongodb://localhost:27017')
db = client.lagou
collection = db.pythonjob
# 请求ajax数据,返回json
json = get_one_page(pagenum)
# 处理返回json数据并保存到的数据库
for item in parse_page(json):
print(item['positionName'])
# 保存到数据库
save_to_db(item, collection)
然后我们利用进程池,快速爬取,这也可能是我被封的原意之一:
GROUP_START = 1
GROUP_STOP = 29
if __name__ == '__main__':
# get_one_page(1)
pool = Pool()
group = ([x for x in range(GROUP_START, GROUP_STOP+1)])
print(group)
pool.map(main, group)
pool.close()
pool.join()
还是一样pycharm里面无法运行,我放到cmd里运行:
到115条的时候就被封了:
结果——数据库:
一共有429条,我只有115条,不甘心啊!
所以我决定之后学了代理池,回来全给它盘下来。
最后给个源码,注意,一定要改cookies
import requests
import json
from pymongo import MongoClient
from multiprocessing import Pool
from urllib.parse import urlencode
import time
def get_one_page(pagenum):
'''
pagemun为页数,获取一页的信息
:param pagenum:
:return json:
'''
params = {
'xl': '本科',
'px': 'default',
'gx': '全职',
'needAddtionalResult': 'false',
'isSchoolJob': '1'
}
data = {
'first': 'false' if pagenum != 1 else 'true',
'kd': 'python',
'pn': pagenum
}
headers = {
'Host': 'www.lagou.com',
'Connection': 'keep-alive',
'Content-Length': '26',
'Origin': 'https://www.lagou.com',
'X-Anit-Forge-Code': '0',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest',
'X-Anit-Forge-Token': 'None',
'Referer': 'https://www.lagou.com/jobs/list_python?px=default&gx=%E5%85%A8%E8%81%8C&gj=&xl=%E6%9C%AC%E7%A7%91&isSchoolJob=1&city=%E5%85%A8%E5%9B%BD',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cookie': 'WEBTJ-ID=20190328100105-169c2078019103-03287e499e7cc-7a1437-1327104-169c207801a0; _ga=GA1.2.1664461408.1553738469; _gid=GA1.2.1954202981.1553738469; user_trace_token=20190328100111-5bf04f0f-50fd-11e9-b40b-525400f775ce; LGUID=20190328100111-5bf053d7-50fd-11e9-b40b-525400f775ce; JSESSIONID=ABAAABAAADEAAFI9211681F55FF42AB9EE85C8EC6C94593; index_location_city=%E5%85%A8%E5%9B%BD; TG-TRACK-CODE=index_search; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22169c40de3e43ad-0357531209afde-7a1437-1327104-169c40de3e524d%22%2C%22%24device_id%22%3A%22169c40de3e43ad-0357531209afde-7a1437-1327104-169c40de3e524d%22%7D; sajssdk_2015_cross_new_user=1; _gat=1; LGSID=20190328201212-b7f050c6-5152-11e9-b9c8-525400f775ce; PRE_UTM=; PRE_HOST=www.baidu.com; PRE_SITE=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DKbms6xfMqIUv7AMjnRPDL-xkTFJ6snHQGL9DF5fQumm%26wd%3D%26eqid%3De29fa16f0000d8bc000000035c9ca96a; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; SEARCH_ID=2798721a148d4f538908ca0bd396d4ac; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1553771063,1553775087,1553775136,1553775450; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1553775450; LGRID=20190328201727-7371eef8-5153-11e9-b831-5254005c3644'
}
base_url = "https://www.lagou.com/jobs/positionAjax.json?"
url = base_url+urlencode(params)
try:
response = requests.post(url, headers=headers, data=data)
print('页面获取成功')
if response.status_code == 200:
# print(response.json())
return response.json()
except requests.ConnectionError as e:
print("error", e.args)
return None
def parse_page(json):
'''
解析收到的信息
:param json:
:return dict:
'''
items = json.get('content').get('positionResult').get('result')
if items:
for item in items:
try:
# job
positionName = item.get('positionName')
positionLables = item.get('positionLables')
salary = item.get('salary')
jobNature = item.get('jobNature')
education = item.get('education')
# company
city = item.get('city')
district = item.get('district')
companyShortName = item.get('companyShortName')
industryField = item.get('industryField')
financeStage = item.get('financ eStage')
companyId = item.get('companyId')
companyLabelList = item.get('companyLabelList')
companySize = item.get('companySize')
except:
pass
else:
yield {
# job
'positionName': positionName,
'positionLables': positionLables,
'salary': salary,
'jobNature': jobNature,
'education': education,
# company
'city': city,
'district': district,
'companyShortName': companyShortName,
'industryField': industryField,
'financeStage': financeStage,
'companyId': companyId,
'companyLabelList': companyLabelList,
'companySize': companySize,
}
def save_to_db(item, collection):
'''
保存数据导数据库
:param item:
:param collection:
:return:
'''
result = collection.insert_one(item)
print(result)
def main(pagenum):
'''
主函数,输入页码
:param pagenum:
:return:
'''
# 链接数据库并选择集合
print('开始第{0}'.format(pagenum))
client = MongoClient('mongodb://localhost:27017')
db = client.lagou
collection = db.pythonjob
# 请求ajax数据,返回json
json = get_one_page(pagenum)
# 处理返回json数据并保存到的数据库
for item in parse_page(json):
print(item['positionName'])
# 保存到数据库
save_to_db(item, collection)
GROUP_START = 1
GROUP_STOP = 29
if __name__ == '__main__':
# get_one_page(1)
pool = Pool()
group = ([x for x in range(GROUP_START, GROUP_STOP+1)])
print(group)
pool.map(main, group)
pool.close()
pool.join()
虽然有点小遗憾,但是我分析ajax进行爬取的能力明显提高了。代码更加规范了,我奖励自己再学一章!
之后学好了,会回来补上缺点的——自动获取最新cookies,利用代理池抗封锁。
想吃石锅鱼。
网友评论