猜测:网站建设,在 推广,反爬,和用户体验这三项功能上会找到一个平衡点.
这是在学院学习期间的第二个项目,也是最后一个,目标是爬取网上的招聘信息,并对信息做分类统计,得出一个招聘方的需求向量,一个福利向量,然后通过某些方法得出应聘方的技能向量,需求向量。最终计算招聘方与应聘方的契合度,排序出最适合应聘方去投递简历的公司。
要做数据分析,首先,需要搞到数据……于是小玉以自己的三脚猫的爬虫水平,瞄准了某gou招聘网站。
先进去看一眼,主体页面长这样:
而且是xhr动态数据加载,接着我们去康康那个动态的请求:
看见响应就很明确了,就是这个请求返回的主体数据,我们要模仿这个请求,就还要查看三个关键位置:1.请求头,2.COOKIE,3.携带的参数
请求头 必须包含:
headers = { # 'Host': 'www.xxxx.com', 'User-Agent': UserAgent().random, # 'Accept': 'application/json, text/Javascript, */*; q=0.01', # 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', # 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', # 第一天尝试时,对方并没有验证此项,后来发现,没有这一项,15条信息与搜索关键字不符。 # 'X-Anit-Forge-Token': 'None', # 'X-Anit-Forge-Code': '0', # 'X-Requested-With': 'XMLHttpRequest', # 'Content-Length': '64', 'Origin': 'https://www.xxxx.com', # 'Connection': 'keep-alive', 'Referer': 'https://www.xxxx.com/jobs/list_python', 'COOKIE': COOKIE, # 'TE': 'Trailers', # 'Pragma': 'no-cache', # 'Cache-Control': 'no-cache' }
请求头里面有一个很明显的数据是COOKIE,这本来也是一项非常关键的参数,我们一起来看一下:
当小玉看见这个COOKIE的时候,直接就傻眼了,这TM都是些啥呀?感觉全是加密的参数呀……
但是小玉灵机一动!直接删除了这个COOKIE,然后刷新网页,重新找到了这个请求的信息一看:
诶,有意思,COOKIE变少了,请求数据一样的响应了,那么这些COOKIE怎么来的呢?于是在HTML请求中直接搜索COOKIE,只看响应COOKIE,还真就找到了一个请求:
幸运的是这个获取COOKIE的请求没有携带任何参数和先决COOKIE,用requests直接向url发起请求就能直接拿到响应的COOKIE
def get_1_COOKIE(): # 返回页面和COOKIE:JSESSIONID,SEARCH_ID,user_trace_token,X_HTTP_TOKEN url_0 = 'http://www.XXXX.com/jobs/list_python' headers_0 = { 'User-Agent': UserAgent().random, 'Referer': 'https://www.XXXXX.com/jobs/list_python', } response = requests.get(url=url_0, headers=headers_0) # 获取requests请求返回的COOKIE COOKIE = requests.utils.dict_from_COOKIEjar(response.COOKIEs) COOKIE_str = '' for k, v in COOKIE.items(): COOKIE_str += f'{k}={v}; ' print(COOKIE_str) return COOKIE_str
3.携带的信息: 我们再来看一下那个xhr的请求所携带的信息(请求体)
经过测试,可以发现,表单里面的sid是可以删除的。嗯没错,结论就是四个字:可以删除。小玉想了想前两天硬着头皮朔源这个sid的时候,真的是快裂开了……至此这个xhr请求已经模拟完成,可以获取每一页的15条招聘信息简要,
def get_15_message(direction, page, COOKIE): """ 返回15条招聘信息的简要 包含 招聘ID:positionId 6884621 招聘名称:positionName 'Python开发工程师' 公司ID:companyId 124262 公司名字:companyFullName 'xxxxx公司' 公司规模:companySize '150-500人' 公司主业:industryField '硬件,其他' 融资阶段:financeStage '不需要融资' or 'A轮' skillLables positionLables industryLables 此三项为技能名称列表,其中内容大致相同,需要取三项并集,有的岗位可能会缺失其中1到2项 ['电商', '算法', '爬虫工程师', 'Python', 'MySQL'] 创建时间: createTime '2020-06-23 11:52:45' 城市:city '上海' 区域:district '徐汇区' 薪水:salary '20k-40k' 工作经验:workYear '3-5年' 学历: education '本科' """ headers = { # 'Host': 'www.xxxx.com', 'User-Agent': UserAgent().random, # 'Accept': 'application/json, text/Javascript, */*; q=0.01', # 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', # 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', # 第一天尝试时,对方并没有验证此项,后来发现,没有这一项,15条信息与搜索关键字不符。 # 'X-Anit-Forge-Token': 'None', # 'X-Anit-Forge-Code': '0', # 'X-Requested-With': 'XMLHttpRequest', # 'Content-Length': '64', 'Origin': 'https://www.XXXXX.com', # 'Connection': 'keep-alive', 'Referer': 'https://www.XXXX.com/jobs/list_python', 'COOKIE': COOKIE, # 'TE': 'Trailers', # 'Pragma': 'no-cache', # 'Cache-Control': 'no-cache' } url = 'https://www.XXXX.com/jobs/positionAjax.json?needAddtionalResult=false' data = requests.post(url=url, headers=headers, data=f'first=true&pn={page}&kd={direction}').text data_json = json.loads(data) print(f'{direction}第{page}页:', data_json) jobs = data_json['content']['positionResult']['result'] return jobs
接下来是爬取每个招聘岗位的详细信息:
这个就比较简单了,为了不走弯路,上来就是删除看不懂的COOKIE,然后发现,这个详细信息,也不需要用到COOKIE
def countents(positionId): """
.*? :该职位全部信息 .*? :职位诱惑 .*? :职位详细描述
.*?
:职位详细描述 :param positionId: 招聘信息ID :return: """ headers = { 'Host': 'www.xxxx.com', 'User-Agent': UserAgent().random, # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', # 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', # 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '0', # 此处原本为1,将其改为0.猜测后端有针对其的累加计数 # 'TE': 'Trailers', # 'Pragma': 'no-cache', # 'Cache-Control': 'no-cache' } url_1 = f'https://www.xxxx.com/jobs/{positionId}.html' data = requests.get(url=url_1, headers=headers).content.decode('utf-8', 'ignore') # 匹配整个详细信息,如果没有,则爬虫被识别 job_detail_obj = re.search(r'
(.*?)', data, flags=re.S) if job_detail_obj: job_detail_all = job_detail_obj.group() else: print(f'https://www.xxxx.com/jobs/{positionId}.html') print('返回数据错误') return None job_advantage_s = re.search(r'(.*?)', job_detail_all, flags=re.S).group() job_advantage_list = re.findall(r'
(.*?)
', job_advantage_s) job_bt_s = re.search(r'(.*?)', job_detail_all, flags=re.S).group() job_bt_list = re.findall(r'
(.*?)
', job_bt_s) if not job_bt_list: job_bt_list.append(job_bt_s) try: job_address = re.search( r'.*?', job_detail_all, flags=re.S).group('addr') except AttributeError: raise ('详细地址错误') return [job_advantage_list, job_bt_list, job_address]
这里我比较喜欢用正则来匹配想要的信息,纯属个人喜好!
至此,数据爬取阶段结束,由于在爬取详细信息的时候没有使用COOKIE,所以对时间间隔的要求非常高(原因是我猜的),我设置的sleep是20秒。反正10秒是不够的。
接下来还有数据存储,数据库设计,数据整理,分析这一最为重要的内容,就不再这篇文章中写了,太难了,我还没想好向量的结构和权重的计算方式……,留作下一篇吧!
最后的最后,聊一聊为什么不使用COOKIE或者使用部分COOKIE也能获得信息呢?网站既然已经发出来一大串的加密COOKIE,那么要对其进行验证,是一件非常简单的事情,那么为什么网站允许没有COOKIE的请求也能获取信息呢?小玉想了很久,只能得出一个大概的猜测:就是文章开头的那一句:网站建设,在 推广,反爬,和用户体验这三项功能上会找到一个平衡点.