原文鏈接:https://zhuanlan.zhihu.com/p/98747651
想要進行數據分析,首先就是要有數據。那么數據如何獲取呢?
當然網上有各種公開的數據或者數據接口,例如政府公開的數據,企業、公益組織公開的數據等等。
但是并不是所有的數據都能從網上找到,這時候就需要我們寫爬蟲來爬取數據(自己動手,豐衣足食嘛)。
學習了數據分析,我們最關心的當然是找工作啦。那么這里就以爬取拉勾網的數據分析職位數據作為實戰,寫一個我們自己的爬蟲。
1 準備工作
我們用到的python庫有:requests和pandas。requests是最常用的構造和解析http請求的庫,pandas是進行數據分析一定會使用的庫,提供了數據分析需要使用的各種工具,這里我們使用的是to_csv來存儲數據。
抓包工具:為了更好地分析請求,建議下載一個抓包工具(也可以直接通過瀏覽器的Network進行分析,但是不如使用抓包工具方便),可以把流量進行重放,便于分析。這里使用的是Burp Suite Free Edition,這也是網絡安全人員常用的工具。
2 分析請求
打開chrome瀏覽器,在網頁中輸入“數據分析“,打開F12。
點擊第一條請求,切換到Preview查看json格式化后到響應,發現這就是我們想要找的請求。
3 Python構造請求
切到Headers,提取出我們需要的信息:請求地址Request URL,請求方式POST,請求body中的數據Form Data。這里還需要把Response Headers中的信息一起帶到請求的Header中,包括瀏覽器信息User-agent、跨域相關的Origin、以及Cookie等信息,總之全部帶過來。
好了,現在我們構造第一條請求
于是我們獲取了第一頁的數據。從請求中可以看到,pn是頁數,那么把pn從1到最后一頁,遍歷一遍,是不是就能爬取所有數據呢?結果是不行。當爬取到第6頁時,返回結果出錯了
原因是沒有content這個鍵值。我們修改下請求,直接打印response
r = requests.post('https://www.lagou.com/jobs/positionAjax.json', headers=headers, params=params, cookies=cookies, data=data)
response = r.json()
print(response)
好吧,說我們操作太頻繁。當然不能這么輕易就讓我們爬取所有數據啦,因為拉勾網使用了反爬策略。
4 分析反爬策略
如何分析反爬策略呢?
這時候我們的抓包工具就出場了。這里就不介紹具體用法了,網上一堆教程(注意這里是https請求,burp需要導入證書)。
我們用抓包工具抓取第一頁和第六頁的請求,發送到comparer中進行比較
標紅的表示cookie中字段發生了變化,同時body中多了一個sid字段。我們知道,cookie中的字段發生變化,通常需要在response頭中使用Set-Cookie來設置。仔細查看歷史請求,下面這條請求引起了我們的注意,把它放到repeater中進一步分析
嘗試把Cookie置空,在響應中會重新Set-Cookie
由此,我們聯想到,是不是當Cookie中某些字段失效的時候,我們只要重新發送這條請求,獲取新的Cookie,就可以繞過反爬策略了?我們修改一下代碼,并引入pandas來存儲結果到csv中
import requests
import time
import pandas as pd
import math
# 獲取新的Cookie
def get_cookie():
? ? headers = {
? ? ? ? 'Accept': 'application/json, text/javascript, */*; q=0.01',
? ? ? ? 'Accept-Encoding': 'gzip, deflate, br',
? ? ? ? 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
? ? ? ? 'Connection': 'keep-alive',
? ? ? ? 'Upgrade-Insecure-Requests': '1',
? ? ? ? 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36',
? ? ? ? 'Sec-Fetch-User': '?1'
? ? }
? ? pre_response = requests.get(
? ? ? ? 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/p-city_3?&cl=false&fromSearch=true&labelWords=&suginput=',
? ? ? ? headers=headers)
? ? cookies = {
? ? ? ? 'user_trace_token': '20191221100243-986eaba8-84ce-47bd-804f-6015e977b6e6',
? ? ? ? 'LGUID': '20190824091904-293ded79-c60d-11e9-a504-5254005c3644',
? ? ? ? 'JSESSIONID': 'ABAAABAABEEAAJA24A5C810F59E6988A2A3495180E65450',
? ? ? ? 'index_location_city': '%E4%B8%8A%E6%B5%B7',
? ? ? ? 'X_HTTP_TOKEN': '42daf4b72327b2813673986751bf5e71415983ed09',
? ? ? ? 'SEARCH_ID': '74d7631fe0ec4f3fa7badce24c42e3be'
? ? }
? ? # 轉成dict
? ? cookie = requests.utils.dict_from_cookiejar(pre_response.cookies)
? ? cookies.update(cookie)
? ? return cookies
# 爬取數據
def get_data(cookies, page):
? ? headers = {
? ? ? ? 'Origin': 'https://www.lagou.com',
? ? ? ? 'X-Anit-Forge-Code': '0',
? ? ? ? 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
? ? ? ? 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36',
? ? ? ? 'X-Requested-With': 'XMLHttpRequest',
? ? ? ? 'X-Anit-Forge-Token': 'None',
? ? ? ? 'Sec-Fetch-Site': 'same-origin',
? ? ? ? 'Sec-Fetch-Mode': 'cors',
? ? ? ? 'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput='
? ? }
? ? # url中的參數
? ? params = {
? ? ? ? 'city': '上海',
? ? ? ? 'needAddtionalResult': 'false'
? ? }
? ? # body中的參數,第一頁和后面頁數參數不同
? ? if page == 1:
? ? ? ? data = {
? ? ? ? ? ? 'first': 'true',
? ? ? ? ? ? 'pn': '1',
? ? ? ? ? ? 'kd': '數據分析'
? ? ? ? }
? ? else:
? ? ? ? data = {
? ? ? ? ? ? 'first': 'false',
? ? ? ? ? ? 'pn': page,
? ? ? ? ? ? 'kd': '數據分析',
? ? ? ? ? ? 'sid': '0144b1f08bdc48c8ba656dc8a18b746c'
? ? ? ? }
? ? r = requests.post('https://www.lagou.com/jobs/positionAjax.json', headers=headers, params=params, cookies=cookies,
? ? ? ? ? ? ? ? ? ? ? data=data)
? ? response = r.json()['content']['positionResult']
? ? result = response['result']
? ? # dict轉成dataFrame
? ? response_to_df = pd.DataFrame.from_dict(result)
? ? global df
? ? # 添加到全局df中
? ? df = df.append(response_to_df, ignore_index=True)
? ? # 獲取總頁數
? ? total_page = math.ceil(response['totalCount'] // response['resultSize'])
? ? # 返回是否已經最后一頁,用來跳出循環
? ? return page >= total_page
# 初始獲取Cookie
cookies = get_cookie()
# 初始化頁數
page = 1
# 創建DataFrame,用于存儲數據
df = pd.DataFrame()
# 循環,直到最后一頁
while (1):
? ? if page % 4 == 0:
? ? ? ? cookies = get_cookie()
? ? end = get_data(cookies=cookies, page=page)
? ? if end:
? ? ? ? break
? ? else:
? ? ? ? page += 1
? ? time.sleep(5)
# 默認encoding=utf-8會導致excel打開亂碼
df.to_csv('lagou.csv', sep=',', header=True, encoding='GBK')
與數據分析相關的還有數據挖掘,我們也來爬一下,一共389條數據
至此,我們完成了第一個爬蟲,獲取了拉勾網上數據分析相關職位的數據。
數據得到了,下一節將會對爬取到的數據進行分析。