这是一次失败的尝试 , 事情是这样的……

1.起因
前段时间刚刚学完爬虫,于是准备找个项目练练手。因为想要了解一下“数据挖掘”的职位招聘现状,所以我打算对‘智联招聘’下手了。网上当然也有很多教程,但是套路基本就是那几种情况,看起来也不是特别困难,我充满信心地开始了尝试。

2.分析网站数据
使用工具:谷歌浏览器、pycharm

首先利用谷歌浏览器查看网页源码,发现在源码里找不到职位信息,所以判断职位信息是通过AJAX方式动态加载的。

于是,我采用谷歌浏览器的开发者工具进行抓包分析数据。

找到动态加载的文件后,分析该数据请求浏览器是怎么完成的。查看数据请求头信息,可以找到请求的URL。再看请求方式,是Post请求。于是分析post请求提交的参数。

_v: 0.14465550
x-zp-page-request-id: 6eed1fcaea9c498bab35d6943c3de160-1584539231050-802211
x-zp-client-id: d09f083d-3339-4053-9687-34318fe5b0f6
MmEwMD: 5HFRnmn4UlsY9o8zY2_zIQ0p5dKimKzxXlr6pjGK……

很显然这是经过加密的几个参数,而且与时间戳有关。网上有关于解密的算法,但是如今的智联网站多了一层加密,就是‘MmEwMD:’参数。而且经过观察,这是几个参数是拼接在网址后面组合成数据请求的URL的,网上没有关于这方面的案例,因此强行爬取怕是不行,臣妾做不到啊!

3.终极爬取方式 - 无头浏览器
既然强攻不行,就不得不用爬虫的终极解决办法,就不信敲不开智联的“大门”。

“工欲善其事,必先利其器。”

因此,这里需要安装第三方库:selenium,并下载配置无头浏览器。有一个坑需要注意,就是pyhton已经不支持 phantomjs,所以我选择了Chromedriver(要与自己的谷歌浏览器版本相匹配)
万事俱备只欠东风,一切准备妥当后,开始爬取尝试。

数次尝试,发现总是报错,一番查看之后发现无头浏览器总是停留在初始页面,职位信息加载不出职位信息,我只好再次通过无头浏览器抓包查看问题出在哪一步。

于是,我发现了动态加载请求文件的方式错了,本该是POST请求,现在提交的是OPTIONS请求,所以返回状态码400的错误。无头浏览器本应于普通浏览器一样,但是这里无头浏览器的请求方式却有变化。

我猜想应该是智联网站采取了更严谨的反爬措施,能够识别无头浏览器。唉,费了老大劲,结果连职位信息的影子都没见着,技艺不精还需继续学习才好!


4.初次爬取,终于失败

从现在来看,要想爬取智联网站有两种方案可行:

1.破解网站加密算法,并模拟加密算法

2.修改无头浏览器请求数据方式,或者获得数据请求参数。

可是,不管哪一种方法,都很难实现。虽然这次没有爬取成功,但这是一次‘顺藤摸瓜’的探索的过程,等到技术精湛的时候再来尝试!

奉上这糟糕的代码:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC # 内置预期条件函数,具体API请参考此小节后API链接
from selenium.webdriver.common.by import By # 内置定位器策略集
#引入按键包
# from selenium.webdriver.common.keys import Keys
from lxml import etree
import time
import hashlib
# import ssl
# ssl._create_default_https_context = ssl._create_unverified_context
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
# 过滤出数据请求中的headers
def getHttpInfo(browser):
    for responseReceived in browser.get_log('performance'):
        try:
            response = json.loads(responseReceived[u'message'])[u'message'][u'params'][u'response']
            if 'ajaxUrl' in response['url']:
                # print(response)
                # print(response['url'])
                # print(response['headers'])
                # print(response['headersText'])
                return response['requestHeaders']
        except:
            pass
    return None
# 请求页面 并设置headers到文件中
def setHeaders():
    d = DesiredCapabilities.CHROME
    d['loggingPrefs'] = { 'performance':'ALL' }
    options=webdriver.ChromeOptions()
    options.set_headless()
    options.add_argument('--disable-gpu')
    driver=webdriver.Chrome(desired_capabilities=d,options=options)
    driver.get('http://www.baidu.com')
    sleep(20)
    headers = getHttpInfo(driver)
    driver.quit()
    # write header
    hand = open('header.txt', 'w')
    hand.write(json.dumps(headers))
    hand.close()
chrome_options = Options()
#后面的两个是固定写法隐藏界面
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 构建浏览器对象
path = r'C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chromedriver.exe'
browser = webdriver.Chrome(executable_path=path,chrome_options=chrome_options)
# 获取网页文件,保存在文件中,page_source为JS动态加载后的页面
url = 'https://sou.zhaopin.com/?jl=765&kw=%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98&kt=3'
# 设置user-agent
user_ag='Win7+ie9:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)'
chrome_options.add_argument('user-agent=%s'%user_ag)
# 隐式的等待
# browser.implicitly_wait(3)
browser.get(url)
# 找到弹窗并点击消除
elem = browser.find_element_by_xpath(r'//div[@class="risk-warning__content"]/button').click()
print(getHttpInfo(browser))
WebDriverWait(browser, 20, 0.5).until(EC.presence_of_all_elements_located((By.CLASS_NAME,'contentpile__content'))) #使用expected_conditions自带验证函数
browser.save_screenshot('zhilain.png')
js = 'document.documentElement.scrollTop=10000'
browser.execute_script(js)
time.sleep(3)
# 保存网页截图
html = browser.page_source
print(html)
browser.get_screenshot_as_file('test.png')
browser.quit()
''' #####解密########(来源于网络)
# 经过分析_v就是一个随机的8位小数
# x-zp-page-request-id 由三部分组成,32位随机数据通过md5简单加密得到+ 当前时间戳 + 随机数6位
# 想办法用python简单实现所谓的加密算法x-zp-page-request-id
# 1、生成一个随机32位数id
md5 = hashlib.md5()
id = str(random.random())
md5.update(id.encode('utf-8'))
random_id = md5.hexdigest()
#  2、生成当前时间戳
now_time = int(time.time() * 1000)
#  3、生成随机6位数
randomnumb = int(random.random() * 1000000)
# 组合代码生成x-zp-page-request-id
x_zp_page_request_id = str(random_id) + '-' + str(now_time) + '-' + str(randomnumb)
# print(x_zp_page_request_id)
# 生成_v
url_v = round(random.random(), 8)
# print(url_v)
'''