python3 爬取百合網的女人們和男人們


學Python也有段時間了,目前學到了Python的類。個人感覺Python的類不應稱之為類,而應稱之為數據類型,只是數據類型而已!只是數據類型而已!只是數據類型而已!重要的事情說三篇。

據書上說一個.py(常量、全局變量、函數、數據類型)文件為一個模塊,那么就有了一種感覺:常量、全局變量、函數、數據類型是同一“級別的”。在此不多說了,收回自己的心思來看爬蟲吧!

1、進百合網官網,單擊“搜索”、單擊“基本搜索”,這時會跳向另一個頁面,該頁面為登錄頁面(如圖):

 

2、找到login.js,具體步驟:F12、F5、network、js(如圖):

 

3、找登錄時的異步請求,該請求在login.js中(如圖):

 

 4、單擊“基本搜索”,會得到兩個異步請求

1:獲取160個id  (如圖):

 

2:根據id得到用戶詳細信息,為json數據(如圖):

 

說了這么多,該上代碼了(總共261行):

baihe.py:

 

 1 #__author: "YuWei"  2 #__date: 2018/2/4  3 import requests  4 import time  5 import pymssql  6 import os  7  8 # 8個人為一組,該常量用於判斷列表的長度是否與網站一致  9 FING_INDEX = 8  10 # 請求頭,偽裝成瀏覽器  11 HEADERS = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'}  12 # 代理ip,防止被百合網封ip  13 HTTP_IP_PROXIES_1 = 'http://211.151.58.5:80'  14 HTTP_IP_PROXIES_2 = 'http://192.168.200.1:8081'  15  16 def baihe_db(personal):  17 """  18  數據庫相關的操作  19  20  :param personal: 為字典類型,封裝着個人具體信息  21  :return: 無  22 """  23 # 數據連接  24 conn = pymssql.connect(host='localhost', user='YUANWEI', password='123456c', database='Baihe',charset='utf8')  25 cur = conn.cursor() # 游標  26 sql = """insert into users values({},'{}',{},'{}','{}','{}',{},'{}','{}','{}','{}');""" \  27 .format(personal['userID'], personal['nickname'], personal['age'], '' if personal['gender'] == "1" else '',  28 personal['cityChn'], personal['educationChn'], personal['height'],  29 '沒房' if personal['housing'] == 0 else '有房', '沒車' if personal['car'] == 0 else '有車',  30 personal['incomeChn'],personal['marriageChn'])  31 print('sql: ', sql)  32 try:  33 cur.execute(sql) # 執行sql語句  34 save_photo(personal, get_miss_photo_binary(personal['headPhotoUrl'])) # 保存頭像  35 print('成功獲取該用戶',personal['userID'])  36 except pymssql.IntegrityError:  37 print('該用戶已存在 ',personal['userID'])  38 except SystemError as sy: # 向err.txt導入錯誤日志  39 with open('err.txt','a',encoding='utf8') as file:  40 file.write(personal['nickname'] + ' ' + str(personal['userID']) + ' 錯誤信息:' + str(sy) + '\n') #  41 except pymssql.ProgrammingError as pp:  42 with open('err.txt','a',encoding='utf8') as file:  43 file.write(personal['nickname'] + ' ' + str(personal['userID']) + ' 錯誤信息:' + str(pp) + '\n')  44 conn.commit() # 提交  45 time.sleep(1)  46  cur.close()  47  conn.close()  48  49 def personal_data(lists):  50 """  51  獲取一組的詳細信息,最多為8個  52  53  :param lists: 列表類型,封裝着一組信息  54  :return: 無  55 """  56 for personal_data_dict in lists: # 遍歷一組信息  57  baihe_db(personal_data_dict)  58  59 def get_miss_photo_binary(photo_url):  60 """  61  獲取照片的二進制數據  62  63  :param photo_url: 個人頭像的url  64  :return: 二進制數據  65 """  66 binary = ''  67 try:  68 # 向服務器發送get請求,下載圖片的二進制數據  69 binary = requests.get(photo_url, headers=HEADERS,proxies={"http": HTTP_IP_PROXIES_2}).content  70 except requests.exceptions.MissingSchema as rem:  71 print(rem)  72 except requests.exceptions.ProxyError: # 代理網絡連接慢或無網絡  73 time.sleep(5)  74 # 遞歸調用get_miss_photo_binary()  75  get_miss_photo_binary(photo_url)  76 return binary  77  78 def save_photo(personal,binary):  79 """  80  以'E:/Baihe/1/'為文件目錄路徑 或 以'E:/Baihe/0/'為文件目錄路徑  81  以 name + id + .jpg 或 以 id + .jpg 為文件名  82  有可能無相片  83  84  :param personal: 字典類型,封裝着個人具體信息  85  :param binary: 二進制數據  86  :return: 無  87 """  88 if binary != '':  89 file_path = 'E:/Baihe/1/' if personal['gender'] == "1" else 'E:/Baihe/0/' #  90 if not os.path.exists(file_path): # 如果該路徑不存在  91 os.makedirs(file_path) # 創建該路徑  92 try:  93 # 向file_path路徑保存圖片  94 with open(file_path + personal['nickname'] + str(personal['userID']) + '.jpg','wb') as file:  95  file.write(binary)  96 except OSError:  97 with open(file_path + str(personal['userID']) + '.jpg','wb') as file:  98  file.write(binary)  99 100 101 def no_exact_division(miss_id_list): 102 """ 103  當包含用戶id的列表長度不能被8整除且列表長度小於8時調用該方法 104 105  :param miss_id_list: 為列表類型,封裝着用戶id 106  :return: 無 107 """ 108 miss_info_lists = ba.get_miss_info(miss_id_list) # 獲取列表的個人信息 109 personal_data(miss_info_lists) # 遍歷一組的信息 110 111 112 class Baihe(object): 113 114 def __init__(self,account,password): 115 """ 116  初始化 117  :param account: 賬號 118  :param password: 密碼 119 """ 120 self.is_begin = True # 開始爬取數據 121 self.index = 0 # 控制self.info長度為8個 122 self.info = [] # 臨時保存用戶id 123 self.page = 61 # 頁碼 124 self.account = account # 賬號 125 self.password = password # 密碼 126 self.req = requests.session() # 會話,保證Cookie一致 127 128 def login(self): 129 """ 130  登錄 131 132  :return: 無 133 """ 134 # 登錄的url 135 url_login = 'http://my.baihe.com/Getinterlogin/gotoLogin?event=3&spmp=4.20.87.225.1049&' \ 136 'txtLoginEMail={}&txtLoginPwd={}'.format(self.account,self.password) 137 login_dict = {} 138 try: 139 # 向服務器發送get請求 140 login_dict = self.req.get(url_login,headers=HEADERS,proxies={"http": HTTP_IP_PROXIES_1},timeout=500).json() 141 except requests.exceptions.ProxyError: # 代理網絡連接慢或無網絡 142 time.sleep(5) 143 # 遞歸調用self.login() 144  self.login() 145 time.sleep(3) 146 print('login: ',login_dict) 147 self.req.keep_alive = False # 關閉會話多余的連接 148 if login_dict['data'] == 1: 149 print('登錄成功') 150 else: 151 print('登錄失敗, 30分鍾以后自動登錄。。。。。。。。') 152 time.sleep(1800) 153 # 遞歸調用self.login() 154  self.login() 155 print('login is cookie ', requests.utils.dict_from_cookiejar(self.req.cookies)) # 查看登錄后的會話cookie 156 157 def filtrate_miss(self,pages): 158 """ 159  根據條件篩選數據,不提供條件參數 160 161  :param pages: 頁碼。該網站只提供62頁的數據 162  :return: 包含160個用戶的id的列表 163 """ 164 time.sleep(2) 165 # 獲取用戶id的url 166 url_miss = 'http://search.baihe.com/Search/getUserID' 167 # from表單數據 168 params_miss = {"minAge": 18, "maxAge": 85, "minHeight": 144, "maxHeight": 210, "education": '1-8', 169 "income": '1-12', "city": -1, "hasPhoto": 1, "page": pages, "sorterField": 1} 170 miss_dict = {} 171 try: 172 # 發送post請求 173 miss_dict = self.req.post(url_miss,data=params_miss,headers=HEADERS,proxies={'http':HTTP_IP_PROXIES_2}).json() 174 except requests.exceptions.ProxyError: # 代理網絡連接慢或無網絡 175 time.sleep(5) 176 # 遞歸調用self.filtrate_miss() 177  self.filtrate_miss(pages) 178 time.sleep(2) 179 print('miss is cookies ', requests.utils.dict_from_cookiejar(self.req.cookies)) # 查看篩選后的會話cookie 180 print('miss dict: ',miss_dict) 181 print(len(miss_dict['data']),'') 182 return miss_dict['data'] 183 184 def get_miss_info(self,infos): 185 """ 186  獲取用戶詳細信息 187 188  :param infos: 列表類型,封裝着個人id,可能為一組(8),或小於8個 189  :return: 包含一組的詳細信息 190 """ 191 if len(infos) == FING_INDEX: # infos列表長度等於8時 192 url_info = 'http://search.baihe.com/search/getUserList?userIDs={},{},{},{},{},{},{},{}'\ 193 .format(infos[0],infos[1],infos[2],infos[3],infos[4],infos[5],infos[6],infos[7]) 194 else: # infos列表長度小於8時 195 bracket = '' # 參數userIDs的值 196 for lens in range(len(infos)): 197 bracket += (str(infos[lens]) + ',') # 構造該表示:"{},{},{},{},{},{},{},{}," 198 # 獲取用戶詳細信息的url bracket[:len(bracket)-1]: 分片,干掉最后一個“,” 199 url_info = 'http://search.baihe.com/search/getUserList?userIDs=' + bracket[:len(bracket)-1] 200 miss_info = {} 201 try: 202 # 發送post請求 203 miss_info = self.req.post(url_info,headers=HEADERS,proxies={'http':HTTP_IP_PROXIES_2}).json() 204 except requests.exceptions.ProxyError: # 代理網絡連接慢或無網絡 205 time.sleep(5) 206 # 遞歸調用self.get_miss_info() 207  self.get_miss_info(infos) 208 time.sleep(2) 209 try: 210 return miss_info['data'] 211 except KeyError: 212 time.sleep(2) 213  self.get_miss_info(infos) 214 215 def exact_division(self,miss_id_list): 216 """ 217  當包含用戶id的列表長度能被8整除或包含用戶id的列表長度不能被8整除且包含用戶id的列表長度大於8 218 219  :param miss_id_list: id信息列表(160) 220  :return: 無 221 """ 222 for user_id in miss_id_list: 223 self.index += 1 224  self.info.append(user_id) 225 if ba.index == FING_INDEX: 226 print('user id: ', self.info) 227 miss_info_list = ba.get_miss_info(self.info) # 8 228 if None != miss_info_list: 229 # 使self.index,self.info為初值,以便8人一組 230 self.index = 0 231 self.info = [] 232 print('miss info list: ', miss_info_list) 233 personal_data(miss_info_list) # 遍歷一組(8)的信息 234 else: 235 print('miss info list is null') 236 continue 237 238 def main(self): 239 """ 240  具體實施 241 242  :return: 無 243 """ 244 self.login() # 登錄 245 while self.is_begin: # 開始 246 print('正在獲取',self.page,'頁.......') 247 miss_id_list = self.filtrate_miss(self.page) # 獲取用戶id列表 248 if len(miss_id_list) != 0: # 列表有id 249 num = len(miss_id_list) % FING_INDEX # 模運算 250 if num == 0: # 被8整除 251  self.exact_division(miss_id_list) 252 else: # 沒有被8整除 , 雖然該分支沒有執行,但還是要加上。因為該網站總是提供160個id 253 print('余數: ',num) 254 if len(miss_id_list) > FING_INDEX: # id列表的長度大於8 255 copy_miss_id_list = miss_id_list[:len(miss_id_list) - num] # 分片 取8個一組 256  self.exact_division(copy_miss_id_list) 257 no_exact_division(miss_id_list[len(miss_id_list) - num:]) # 余下的個人信息 258 else: 259 no_exact_division(miss_id_list) # 小於8個人的個人的信息 260 else: 261 print('數據已爬完。。。。。') 262 self.is_begin = False 263 self.page += 1 264 time.sleep(10) 265 # 運行 266 if __name__ == '__main__': 267 ba = Baihe('xxxxxxx', 'xxxxxxxxxx') 268 ba.main()

 

 

溫馨提示:想爬女的,就找個性別為男的賬號。想爬男的,就找個性別為女的賬號。

 

 如果要簡單的分析一下所爬的數據,建議用男的賬號,女的賬號反復爬那么3-5次,這樣數據才有有效性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM