python3 爬取百合网的女人们和男人们

Posted YuW

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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次,这样数据才有有效性。

以上是关于python3 爬取百合网的女人们和男人们的主要内容,如果未能解决你的问题,请参考以下文章

基于爬取百合网的数据,用matplotlib生成图表

scrapy按顺序启动多个爬虫代码片段(python3)

scrapy主动退出爬虫的代码片段(python3)

潮女 | 比男人帅的 Ruby Rose,机车背心加刺青你也应该试试

那些在开源世界顶半边天的女同胞们

这个男人坚持了八年,撑起了无数人的IT之梦!