又是一年雙十一了,不知道從什么時候開始,雙十一從“光棍節”變成了“雙十一購物狂歡節”,最后一個屬於單身狗的節日也成功被攻陷,成為了情侶們送禮物秀恩愛的節日。
翻着安靜到死寂的聊天列表,我忽然驚醒,不行,我們不能這樣下去,光羡慕別人有什么用,我們要行動起來,去找自己的幸福!!!
我也想“談不分手的戀愛” !!!內牛滿面!!!
注冊登陸一氣呵成~
篩選條件,嗯...性別女,年齡...18到24歲,身高嘛,無所謂啦,就按默認155-170吧,地區...嗯北京好,北京近一點,照片?那肯定要啊,必須的!!!
小姐姐們我來了~
哇,好多小姐姐啊,到底該選哪個搭訕啊.......
這時候就該我們的爬蟲出場了
爬蟲部分
爬蟲部分還是我們之前的四步:分析目標網頁,獲取網頁內容,提取關鍵信息,輸出保存
1. 首先分析目標網頁
按F12召喚開發者工具頁面,切換到Network選項,然后在翻頁的時候抓包,成功截獲請求URL。
不過,這個請求是 POST 方法的,和我們之前見到的 GET 方法的請求有點不同。哪里不同呢......它有點短?
沒錯,它太短了,少了很多信息,比如我們搜索的條件,甚至連頁碼的信息都沒有,光靠它怎么可能正確的找到小姐姐嘛!
別急,往下翻,其實, POST 方法請求的參數是放在 Form Data 的地方(怎么可能沒有嘛是吧)
PS:除了這些之外,還有更多更細的篩選條件
更多篩選條件及其對應的編號
1 2 3 4 5 6 7 8 9 10
地區 年齡 身高 學歷 月薪 婚史 購房 購車 籍貫 戶口
11 12 12 14 15 16 17 18 22 23
民族 宗教信仰 有無子女 職業 公司類型 生肖 星座 血型 誠信等級 照片
構造完整的請求的 URL ,
http://search.jiayuan.com/v2/search_v2.php?key=&sex=f&stc=1:11,2:18.24,3:155.170,23:1&sn=default&sv=1&p=1&f=select
訪問,沒問題,改變p的值,訪問,沒問題,OK本階段完成。
2. 解析網頁內容
通過上面的url,我們可以獲取到服務器返回的 json格式的用戶信息。代碼如下:
import requests def fetchURL(url): ''' 功能:訪問 url 的網頁,獲取網頁內容並返回 參數: url :目標網頁的 url 返回:目標網頁的 html 內容 ''' headers = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', 'Cookie': 'guider_quick_search=on; SESSION_HASH=f09e081981a0b33c26d705c2f3f82e8f495a7b56; PHPSESSID=e29e59d3eacad9c6d809b9536181b5b4; is_searchv2=1; save_jy_login_name=18511431317; _gscu_1380850711=416803627ubhq917; stadate1=183524746; myloc=11%7C1101; myage=23; mysex=m; myuid=183524746; myincome=30; COMMON_HASH=4eb61151a289c408a92ea8f4c6fabea6; sl_jumper=%26cou%3D17%26omsg%3D0%26dia%3D0%26lst%3D2018-11-07; last_login_time=1541680402; upt=4mGnV9e6yqDoj%2AYFb0HCpSHd%2AYI3QGoganAnz59E44s4XkzQZ%2AWDMsf5rroYqRjaqWTemZZim0CfY82DFak-; user_attr=000000; main_search:184524746=%7C%7C%7C00; user_access=1; PROFILE=184524746%3ASmartHe%3Am%3Aimages1.jyimg.com%2Fw4%2Fglobal%2Fi%3A0%3A%3A1%3Azwzp_m.jpg%3A1%3A1%3A50%3A10; pop_avatar=1; RAW_HASH=n%2AazUTWUS0GYo8ZctR5CKRgVKDnhyNymEBbT2OXyl07tRdZ9PAsEOtWx3s8I5YIF5MWb0z30oe-qBeUo6svsjhlzdf-n8coBNKnSzhxLugttBIs.; pop_time=1541680493356' } try: r = requests.get(url, headers=headers) r.raise_for_status() r.encoding = 'unicode_escape' print(r.url) return r.text except requests.HTTPError as e: print(e) print("HTTPError") except requests.RequestException as e: print(e) except: print("Unknown Error !") if __name__ == '__main__': url = 'http://search.jiayuan.com/v2/search_v2.php?key=&sex=f&stc=2:18.24,3:155.170,23:1&sn=default&sv=1&p=1&f=select' html = fetchURL(url) print(html)
在這里有幾個需要注意的點:
① 網站的搜索功能是需要登陸的,否則會一直彈框提示登陸,所以我只好注冊了個賬號,登陸后將 cookie 放入爬蟲的請求頭中,這樣便可正確訪問數據(不過在爬蟲爬取過程中,我發現其實不需要登陸也可以獲取,我是不是虧了?!!)
②直接打開請求返回的結果,其實是不能“看”的,通篇沒一個漢字,都是各種類似於亂碼的東西,這其實是一種 unicode 編碼,將漢字轉化成 \u 開頭的一串字符。
想要解碼成漢字也很容易,只需要將 response 的編碼方式 encoding 設定為 unicode_escape 即可。
r = requests.get(url, headers=headers) r.raise_for_status() r.encoding = 'unicode_escape' print(r.text)
③為了盡可能多一點的尋找,我決定將“地區”這一條件限制去掉,重新訪問,果然,搜到的小姐姐由原先的 3229 瞬間漲到了 59146 ,這下可以開心的爬了。
3.提取關鍵信息
通過分析上面獲取到的 josn 文件,我們可以知道,這里面包含了用戶的相當多的信息,包括用戶ID,昵稱,性別,年齡,身高,照片,學歷,城市,擇偶標准,以及個性宣言等(不過有些信息在這里是獲取不到的,需要進入個人主頁才能查看,比如收入等)。
import json def parserHtml(html): ''' 功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容 參數: html:類似文件的內存 HTML 文本對象 ''' s = json.loads(html) usrinfo = [] for key in s['userInfo']: blist = [] uid = key['uid'] nickname = key['nickname'] sex = key['sex'] age = key['age'] work_location = key['work_location'] height = key['height'] education = key['education'] matchCondition = key['matchCondition'] marriage = key['marriage'] income = key['income'] shortnote = key['shortnote'] image = key['image'] blist.append(uid) blist.append(nickname) blist.append(sex) blist.append(age) blist.append(work_location) blist.append(height) blist.append(education) blist.append(matchCondition) blist.append(marriage) blist.append(income) blist.append(shortnote) blist.append(image) usrinfo.append(blist) print(nickname,age,work_location) #writePage(usrinfo) print('---' * 20)
部分運行結果如下:
http://search.jiayuan.com/v2/search_v2.php?key=&sex=f&stc=2:18.24,3:155.170,23:1&sn=default&sv=1&p=1&f=select
小文文 23 西安
還單身的糖豆 18 濟南
小了白了兔 24 懷化
小雅xy 24 深圳
惜夢緣 23 杭州
冬季 24 南京
qian141 21 石家庄
浪人心傷 24 閔行
高挑的檸檬 24 長沙
甜甜 23 鄭州
------------------------------------------------------------
http://search.jiayuan.com/v2/search_v2.php?key=&sex=f&stc=2:18.24,3:155.170,23:1&sn=default&sv=1&p=2&f=select
蘑菇 24 武漢
低調宅女 24 南京
女士 21 南京
遠處的一抹光 23 南京
娜娜 24 河北
我最喜歡你 24 洛陽
愛笑的香菇 24 廣州
LLS 24 惠州
值得 24 無錫
宿媛 23 江北
------------------------------------------------------------
4. 保存輸出文件
最后,只需要把提取出的信息寫入csv文件,即可完成本次爬取的工作。下面是完整代碼:
import requests import json import time def fetchURL(url): ''' 功能:訪問 url 的網頁,獲取網頁內容並返回 參數: url :目標網頁的 url 返回:目標網頁的 html 內容 ''' headers = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', 'Cookie': 'guider_quick_search=on; SESSION_HASH=f09e081981a0b33c26d705c2f3f82e8f495a7b56; PHPSESSID=e29e59d3eacad9c6d809b9536181b5b4; is_searchv2=1; save_jy_login_name=18511431317; _gscu_1380850711=416803627ubhq917; stadate1=183524746; myloc=11%7C1101; myage=23; mysex=m; myuid=183524746; myincome=30; COMMON_HASH=4eb61151a289c408a92ea8f4c6fabea6; sl_jumper=%26cou%3D17%26omsg%3D0%26dia%3D0%26lst%3D2018-11-07; last_login_time=1541680402; upt=4mGnV9e6yqDoj%2AYFb0HCpSHd%2AYI3QGoganAnz59E44s4XkzQZ%2AWDMsf5rroYqRjaqWTemZZim0CfY82DFak-; user_attr=000000; main_search:184524746=%7C%7C%7C00; user_access=1; PROFILE=184524746%3ASmartHe%3Am%3Aimages1.jyimg.com%2Fw4%2Fglobal%2Fi%3A0%3A%3A1%3Azwzp_m.jpg%3A1%3A1%3A50%3A10; pop_avatar=1; RAW_HASH=n%2AazUTWUS0GYo8ZctR5CKRgVKDnhyNymEBbT2OXyl07tRdZ9PAsEOtWx3s8I5YIF5MWb0z30oe-qBeUo6svsjhlzdf-n8coBNKnSzhxLugttBIs.; pop_time=1541680493356' } try: r = requests.get(url, headers=headers) r.raise_for_status() r.encoding = 'unicode_escape' print(r.url) return r.text except requests.HTTPError as e: print(e) print("HTTPError") except requests.RequestException as e: print(e) except: print("Unknown Error !") def parserHtml(html): ''' 功能:根據參數 html 給定的內存型 HTML 文件,嘗試解析其結構,獲取所需內容 參數: html:類似文件的內存 HTML 文本對象 ''' s = json.loads(html) usrinfo = [] for key in s['userInfo']: blist = [] uid = key['uid'] nickname = key['nickname'] sex = key['sex'] age = key['age'] work_location = key['work_location'] height = key['height'] education = key['education'] matchCondition = key['matchCondition'] marriage = key['marriage'] income = key['income'] shortnote = key['shortnote'] image = key['image'] blist.append(uid) blist.append(nickname) blist.append(sex) blist.append(age) blist.append(work_location) blist.append(height) blist.append(education) blist.append(matchCondition) blist.append(marriage) blist.append(income) blist.append(shortnote) blist.append(image) usrinfo.append(blist) print(nickname,age,work_location) writePage(usrinfo) print('---' * 20) def writePage(urating): ''' Function : To write the content of html into a local file html : The response content filename : the local filename to be used stored the response ''' import pandas as pd dataframe = pd.DataFrame(urating) dataframe.to_csv('Jiayuan_UserInfo.csv', mode='a', index=False, sep=',', header=False) if __name__ == '__main__': for page in range(1, 5916): url = 'http://search.jiayuan.com/v2/search_v2.php?key=&sex=f&stc=2:18.24,3:155.170,23:1&sn=default&sv=1&p=%s&f=select' % str(page) html = fetchURL(url) parserHtml(html) # 為了降低被封ip的風險,每爬100頁便歇5秒。 if page%100==99: time.sleep(5)
后續工作
1. 文件去重
花了兩個多小時,爬了5千多頁,爬到了接近六萬條數據,本來是一個相當開心的事情,但是當我打開文件,按 用戶ID 排序之后,發現!!!!
神魔鬼!!!居然有大量重復的數據,單就這個叫 “名芳” 的用戶,便有兩千多條,這能得了?!!!
為了驗證是不是我程序哪兒出錯了,我反復檢查調試了很久。
我發現,如果只爬前100頁的數據,則重復率較低,而100頁之后,便開始大量的出現重復用戶了;而且重復的數據並不是同一頁中連續出現,而是來自不同頁。
百思不得其解,遂求助大佬,大佬聽完我的描述之后說,會不會是網站的數據本身便是有問題的?
為了解開這個疑惑,我決定去網站上手動查找,一探究竟,到底在100頁之后,發生了什么事兒。
此網站的翻頁功能用的相當蹩腳,只有首頁,上一頁和下一頁,頁碼跳轉也每次只能選擇前后5頁。點了好久終於到了一百多頁之后,發現了一件令人震驚的事情。
這是我隨手截的三頁的截圖,108頁,109頁,和110頁,圖片下方有截圖為證,來感受一下,跟連連看似的。
好吧,同樣的用戶換個順序來湊頁數是嗎,我現在就想看看去重之后究竟還剩多少個。
import pandas as pd inputfile = "Jiayuan_UserInfo.csv" outputfile = "Jiayuan_UserInfo_output.csv" df = pd.read_csv(inputfile,encoding='utf-8',names=['uid','nickname','sex','age','work_location','height','education','matchCondition','marriage','income','shortnote','image']) datalist = df.drop_duplicates() datalist.to_csv(outputfile,encoding='utf-8',index=False, header=False) print("Done!")
下面是運行結果:
堂堂接近6萬人的搜索結果,去重之后居然只剩下不到1000人,再回頭看看看看網站上 “有 59352 人符合條件”,是不是感覺啪啪打臉呢。用這種手段來營造用戶量很大的假象,高明的很吶。
2.照片下載
拋開數據作假不說,我們此行的目的可是看小姐姐來的呢!
言歸正傳,我們來下載小姐姐們的照片咯,照片的鏈接在我們之前保存的csv文件中就有。
import requests import pandas as pd # 讀取csv文件 userData = pd.read_csv("Jiayuan_UserInfo_output.csv",names=['uid','nickname','sex','age','work_location','height','education','matchCondition','marriage','income','shortnote','image']) for line in range(len(userData)): url = userData['image'][line] img = requests.get(url).content nickname = re.sub("[\s+\.\!\/_,$%^*(+\"\'?|]+|[+——!,。?、~@#¥%……&*()▌]+", "",userData['nickname'][line]) filename = str(line) + '-' + nickname + '-' + str(userData['height'][line]) + '-' + str(userData['age'][line]) + '.jpg' try: with open('images_output/' + filename, 'wb') as f: f.write(img) except: print(filename) print("Finished!")
為了方便辨認,我這里將 序號 + 用戶昵稱 + 身高 + 年齡 作為圖片的文件名
這里有一點需要注意的是,用戶昵稱中可能會包含一些奇形怪狀的字符,以它們作為文件名的話,在保存文件的時候會出現異常,所以這里先將用戶名做了一些處理,剔除其中的標點符號等字符,並且做了一個異常處理,即如果出現異常,則輸出該文件名,並繼續保存下一個。
於是乎,我得到了 996 張小姐姐的照片。。。
不過,這些已經不重要了,
這次,我不僅順利爬到了全部小姐姐的數據,還發現了網站的一點“小秘密”。
此時的我無比的膨脹,我覺得我很牛逼
我覺得她們都配不上我。
---------------------
作者:機靈鶴
來源:CSDN
原文:https://blog.csdn.net/wenxuhonghe/article/details/83904396
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!