今天我们打算爬取一下字节跳动的招聘信息:
我们打开开发者工具并访问:
https://jobs.bytedance.com/experienced/position?keywords=&category=&location=&project=&type=&job_hot_flag=¤t=1&limit=10
这次访问监控到的数据很多,其中这个posts接口才有我们需要的json数据:
观察响应头发现一个重要参数csrf:
说明字节跳动的网站具备csrf校验的功能,后文将再介绍如何获取到这个csrf的token。
查看请求参数:
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:810735403
参数包装函数
为了正常爬取时的方便,我们需要先将上面需要的参数,组织成python能够识别的字典形式。直接复制粘贴有很多需要加双引号的地方,但我们可以编程解决这个问题。
首先,定义一个处理函数:
import re
def warp_heareder(s):
print("{")
lines = s.splitlines()
for i, line in enumerate(lines):
k, v = line.split(": ")
if re.search("[a-zA-Z]", k):
k = f'"{k}"'
if re.search("[a-zA-Z]", v):
v = f'"{v}"'
print(f" {k}: {v},")
print("}")
处理请求头:
处理post请求数据:
csrf校验值获取
首先,清空cookie:
然后刷新页面,查看网络请求的抓包情况:
找啊找,终于找到了一个set-cookie的响应头,而且这个设置cookie参数包括了csrf的设置。那么这个接口我们就可以用来作为获取csrf校验值的接口。
使用session保存响应头设置的cookie:
import requests
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Origin': 'https://jobs.bytedance.com',
'Referer': f'https://jobs.bytedance.com/experienced/position?keywords=&category=&location=&project=&type=&job_hot_flag=¤t=1&limit=10'
}
data = {
"portal_entrance": 1
}
url = "https://jobs.bytedance.com/api/v1/csrf/token"
r = session.post(url, headers=headers, data=data)
r
结果:
<Response [200]>
查看获取到的cookie:
cookies = session.cookies.get_dict()
cookies
结果:
{
'atsx-csrf-token': 'RDTEznQqdr3O3h9PjRdWjfkSRW79K_G16g85FrXNxm0%3D'}
显然这个token相对真实需要的存在url编码,现在对它进行url解码:
from urllib.parse import unquote
unquote(cookies['atsx-csrf-token'])
结果:
'RDTEznQqdr3O3h9PjRdWjfkSRW79K_G16g85FrXNxm0='
开始爬取第一页的数据
有了token我们就可以顺利的直接访问接口了:
import requests
import json
headers = {
"Accept": "application/json, text/plain, */*",
"Host": "jobs.bytedance.com",
"Origin": "https://jobs.bytedance.com",
"Referer": "https://jobs.bytedance.com/experienced/position?keywords=&category=&location=&project=&type=&job_hot_flag=¤t=1&limit=10",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
"x-csrf-token": unquote(cookies['atsx-csrf-token']),
}
data = {
"job_category_id_list": [],
"keyword": "",
"limit": 10,
"location_code_list": [],
"offset": 0,
"portal_entrance": 1,
"portal_type": 2,
"recruitment_id_list": [],
"subject_id_list": []
}
url = "https://jobs.bytedance.com/api/v1/search/job/posts"
r = session.post(url, headers=headers, data=json.dumps(data))
r
结果:
<Response [200]>
响应码是200,说明已经顺利通过了校验,现在查看一下数据结构:
r.json()
结果:
使用Pandas对json数据进行处理
import pandas as pd
df = pd.DataFrame(r.json()['data']['job_post_list'])
df.head(3)
结果:
然后我们对各列提取出我们需要的数据:
df.city_info = df.city_info.str['name']
df.recruit_type = df.recruit_type.str['parent'].str['name']
tmp = []
for x in df.job_category.values:
if x['parent']:
tmp.append(f"{x['parent']['name']}-{x['name']}")
else:
tmp.append(x['name'])
df.job_category = tmp
df.publish_time = df.publish_time.apply(lambda x: pd.Timestamp(x, unit="ms"))
df.head(2)
结果:
再删除一些,明显没有任何用的列:
df.drop(columns=['sub_title', 'job_hot_flag', 'job_subject'], inplace=True)
df.head()
结果:
爬取字节跳动全部职位信息
有了上面的测试基础,我们就可以组织一下完整的爬取代码:
import requests
from urllib.parse import unquote
import pandas as pd
import time
import os
session = requests.session()
page = 1500
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Origin': 'https://jobs.bytedance.com',
'Referer': f'https://jobs.bytedance.com/experienced/position?keywords=&category=&location=&project=&type=&job_hot_flag=¤t=1&limit={page}'
}
data = {
"portal_entrance": 1
}
url = "https://jobs.bytedance.com/api/v1/csrf/token"
r = session.post(url, headers=headers, data=data)
cookies = session.cookies.get_dict()
url = "https://jobs.bytedance.com/api/v1/search/job/posts"
headers["x-csrf-token"] = unquote(cookies["atsx-csrf-token"])
data = {
"job_category_id_list": [],
"keyword": "",
"limit": page,
"location_code_list": [],
"offset": 0,
"portal_entrance": 1,
"portal_type": 2,
"recruitment_id_list": [],
"subject_id_list": []
}
for i in range(11):
print(f"准备爬取第{i}页")
data["offset"] = i*page
r = None
while not r:
try:
r = session.post(url, headers=headers,
data=json.dumps(data), timeout=3)
except Exception as e:
print("访问超时!等待5s", e)
time.sleep(5)
df = pd.DataFrame(r.json()['data']['job_post_list'])
if df.shape[0] == 0:
print("爬取完毕!!!")
break
df.city_info = df.city_info.str['name']
df.recruit_type = df.recruit_type.str['parent'].str['name']
tmp = []
for x in df.job_category.values:
if x['parent']:
tmp.append(f"{x['parent']['name']}-{x['name']}")
else:
tmp.append(x['name'])
df.job_category = tmp
df.publish_time = df.publish_time.apply(
lambda x: pd.Timestamp(x, unit="ms"))
df.drop(columns=['sub_title', 'job_hot_flag', 'job_subject'], inplace=True)
df.to_csv("bytedance_jobs.csv", mode="a", header=not os.path.exists("bytedance_jobs.csv"), index=False)
print(",".join(df.title.head(10)))
# 对结果去重
df = pd.read_csv("bytedance_jobs.csv")
df.drop_duplicates(inplace=True)
df.to_csv("bytedance_jobs.csv", index=False)
print("共爬取", df.shape[0], "行无重复数据")
结果:
仅7.3秒爬完了字节跳动1W+以上的职位信息。
可以读取看看:
import pandas as pd
df = pd.read_csv("bytedance_jobs.csv")
df
结果:
有1万个以上的职位信息。
在这里还是要推荐下我自己建的Python开发交流学习(qq)群:810735403
,群里都是学Python开发的,如果你正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2021最新的Python进阶资料和高级开发教程,欢迎进阶中和想深入Python的小伙伴!
**以下内容无用,为本篇博客被搜索引擎抓取使用
(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)
python 是干什么的 零基础学 python 要多久 python 为什么叫爬虫
python 爬虫菜鸟教程 python 爬虫万能代码 python 爬虫怎么挣钱
python 基础教程 网络爬虫 python python 爬虫经典例子
python 爬虫
(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)(* ̄︶ ̄)( ̄︶ ̄)( ̄︶ ̄)
以上内容无用,为本篇博客被搜索引擎抓取使用