学习爬虫的常见问题分享(三)---爬虫遇坑之旅

今天继续跟大家分享我的爬虫进阶之旅。相信各位看到过很多网友分享的求职网站上职位信息的爬取案例,其中爬取拉勾网的案例最多了。加上本身最近也打算换工作,今天就来爬取拉勾网的求职信息吧。缘以为这个网站信息爬取是很简单的,一个招聘网站吗,能有啥技术含量的,结果却让我大跌眼镜,且听我慢慢道来。

案例二:求职网站职位的爬取。
目标:爬取拉勾网上所有“”数据分析“”岗位的招聘信息。
打开lago.com,输入“数据分析“,点击搜索,F12打开网页源码,很容易看出网页上各个招聘岗位的信息很容在HTML代码中找到对应的信息,如公司名称对应的是class名称为company_name的

元素 之间的文本,似乎爬取的难度不大。

在这里插入图片描述
于是很快动手写出的代码如下:

import requests
from bs4 import BeautifulSoup

url='https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput=' #待爬取的网址
h={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'} #虽然不是必须,带上hearders是个好习惯
htmlfile=requests.get(url,headers=h)
objsoup=BeautifulSoup(htmlfile.text,'lxml')

divCompanyname=objsoup.findAll('DIV',class_='company_name') #查找class名称为company_name的<DIV></DIV>元素
for i in divCompanyname:
    aCompany=i.find('a')
    companyname=aCompany.getText()
    print(companyname)
    
len(divCompanyname)

悲催的是,上面这段代码运行时没用结果,即爬取的class名称为company_name的

元素列表divCompanyname是空白的,这从最后一行len(divCompanyname)结果为0可以确定。怎么会这样呢?
运行print(objsoup)打印BeautifulSoup解析对象,然后在其中搜索网页上任一公司名称,如“”快手“”,查不到,这说明网站采用了反爬虫措施,requests库的get请求结果中没有我们需要的岗位信息。真是一个不小的坑呢!

在这里插入图片描述

继续分析网页源码吧。之前看到过有文章提到拉勾网的职位信息是以json格式提供的,于是从源码中发现,Network下的XHR标签下有一个请求的Preview标签下,出现了json格式的职位信息,看来拉勾采用了Ajax技术。此时有点小激动,应该可以直接用requests库的json解码器.json()直接获取吧,有其他网友分享过这样操作的。我双击打开这个请求的链接(见上图红色框处),你猜结果怎么着:在这里插入图片描述
用requests库请求,也得到同样的结果,json解码器排不上用场了。哎,真是坑爹啊。不得不说拉勾不愧是互联网求职公司,还是挺有技术含量的。上图的内容表明网站采取了反爬虫措施起。该怎么办呢?
从技术的角度而言,可以采用的一个办法是用cookie。这里直接 给出代码,大家可以自行分析:

import requests
import json

'''利用session对象的cookies信息跳过反爬虫,然后用json获取数据'''

#用来获取拉勾的cookies
url0 = 'https://www.lagou.com/jobs/list_python%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput='
h={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',\
    'Referer': 'https://www.lagou.com/jobs/list_python%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput='}
session = requests.session()
session.get(url=url0,headers=h)
cookies = session.cookies
cookies.get_dict()

#待爬取的网址
para={'first': 'true','pn': 1,'kd': '数据分析'}
url='https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
req=requests.post(url,cookies=cookies,headers=h,data=para) #注意是post和相应的参数,不是get
req.status_code
js=req.json()
type(js)
print(js)

#打印信息
for result in js['content']['positionResult']['result']:
    positionName = result['positionName']
    createTime = result['createTime']
    companyShortName =result['companyShortName']
    workYear = result['workYear']
    city = result['city']
    salary = result['salary']
    positionLables = result['positionLables']
    positionLables= ','.join(positionLables)
    positionAdvantage = result['positionAdvantage']
    print(positionName,companyShortName,workYear,city,salary,positionLables,positionAdvantage)

这个代码是可以运行的,也可以获得json格式的岗位信息,通过最后一段类似字典的操作获得相应职位信息并打印。貌似这个案例应该结束了。对吗?别急,还没有。在网站面页下方有下一页链接可以点击进入下一页,一共有30页。做爬虫,当然要把这30页的内容都给爬了吧。只要将上述代码中para={‘first’: ‘true’,‘pn’: 1,‘kd’: ‘数据分析’}的‘pn’通过循环1-30即可解决。请大家自行完成完整代码。这是第一种办法。

第二个方法是使用Selenium。利用Selenium暴力爬取到的网页内容,是包含有职位信息的(这点不像requests),同时利用自动点击下一页,获取更新的面页,从而继续爬取新面页的信息。Selenium不愧是爬虫的王者啊。实际上本人在实际操作的时候,也碰到了不少的坑,如爬了几页的时候,网页自动跳转到登录的面页,于是爬虫被终止。还有因为写入文件时的编码错误被终止的情况,以及最初无法实现自动翻页的问题,还有运行时只得到前两页的内容。最终都被一一解决了,其中登录的问题,是增加停止30秒时间内完成收到登录的,编码问题在open文件时加入encoding='utf-8’语句解决了,自动翻页采用了browser.execute_script(“arguments[0].click();”,nextpage)语句,直接的browser.click()貌似未起作用。只得到前两页面页信息的问题,经过排查,找到是不小心将翻页代码放入单页信息爬取的内循环里了(当然这是本人的失误,不是网站坑人,相信很多人犯过类似的错误)。具体实现过程请看如下代码及附带的注释:

import csv
import requests
import time
from selenium import webdriver

browser=webdriver.Chrome('chromedriver.exe')
url='https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/p-city_6?px=default#filterBox'
browser.get(url)
type(browser)
with open('dataanylist.csv','a',newline='',encoding='utf-8') as file:
    writer=csv.writer(file)
    writer.writerow(['comanpy name','salary','posttion name','salary & experience','industry','postion','benefit'])
#等待手动登录
time.sleep(30)
           

#如下循环将爬取结果写入csv文件
numJob=0 #统计数量
for i in range(31):    
    #公司名称,岗位及薪资
    tagli=browser.find_elements_by_tag_name('li')
    len(tagli)
    for i in tagli:
        if i.get_attribute('data-company'):
           numJob+=1#统计爬取结果数量 
           with open('dataanylist.csv','a',newline='',encoding='utf-8') as file:
                writer=csv.writer(file)  
                writer.writerow([i.get_attribute('data-company'),i.get_attribute('data-salary'),i.get_attribute('data-positionname'),\
                              i.find_element_by_class_name('list_item_top').find_element_by_class_name('li_b_l').text,\
                              i.find_element_by_class_name('list_item_top').find_element_by_class_name('industry').text,\
                              i.find_element_by_class_name('list_item_bot').find_element_by_class_name('li_b_l').text,\
                              i.find_element_by_class_name('list_item_bot').find_element_by_class_name('li_b_r').text\
                              ])
                       
    #这里如下部分的位置很重要,不能放在内循环,否则只停留在一个面页,太他妈的坑爹了,让我痛苦了很久很久,看来写程序前把逻辑先整理好,非常重要!
    numJob+=1
    nextpage= browser.find_element_by_class_name('pager_next')
    browser.execute_script("arguments[0].click();",nextpage) #如果这里直接用nextpage.click()会出错,因为有很多nextpage?
    time.sleep(5)        

print(numJob) #统计岗位条数  

到此拉勾网站的爬虫算比较成功了,经过多次尝试解决一个又一个坑。坦白说,这些问题对新手来说不太容易解决的,所以建议大家学习时多个他人交流,以尽快解决问题。
上述案例,其实还有待提升的空间:
1、想实现自动登录系统的功能,理论是可行的,不过有由于Selenium打开拉勾网页的时候,会自动弹出一个新的窗口供用户登录,这点我暂时未实现。
2、虽然Selenium可以暴力爬取信息,但是它爬取的岗位信息还是有限的。比如点击每个岗位弹出新的网页里还有该岗位完整的岗位要求和工作内容等信息,这些信息希望也能爬取用于后期的分析。虽然selenium理论上可以拿到每个岗位详详细信息的链接,并逐一爬取,不过从技术上需要实现Selenium在同一个窗口打开每个岗位面页的功能;否则,爬取时会打开数百个窗口,这样的话如果爬取一个面页后不关闭浏览器,容易造成死机。所以貌似需要用到更强大的爬虫框架-Scrapy了,这也是后期需要分享的话题了。
爬虫要注意不要恶意增加网站服务器的负担,注意增加等待的时间。
本人也再次声明一下,以上内容仅供学习交流用途,无侵犯网站隐私的意图。如有不妥,请告知。
欢迎大家跟我交流!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值