学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=‘13974162858x‘, 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 conn.commit() # 提交
42 time.sleep(1)
43 cur.close()
44 conn.close()
45
46 def personal_data(lists):
47 """
48 获取一组的详细信息,最多为8个
49
50 :param lists: 列表类型,封装着一组信息
51 :return: 无
52 """
53 for personal_data_dict in lists: # 遍历一组信息
54 baihe_db(personal_data_dict)
55
56 def get_miss_photo_binary(photo_url):
57 """
58 获取照片的二进制数据
59
60 :param photo_url: 个人头像的url
61 :return: 二进制数据
62 """
63 binary = ‘‘
64 try:
65 # 向服务器发送get请求,下载图片的二进制数据
66 binary = requests.get(photo_url, headers=HEADERS,proxies={"http": HTTP_IP_PROXIES_2}).content
67 except requests.exceptions.MissingSchema as rem:
68 print(rem)
69 except requests.exceptions.ProxyError: # 代理网络连接慢或无网络
70 time.sleep(5)
71 # 递归调用get_miss_photo_binary()
72 get_miss_photo_binary(photo_url)
73 return binary
74
75 def save_photo(personal,binary):
76 """
77 以‘E:/Baihe/1/‘为文件目录路径 或 以‘E:/Baihe/0/‘为文件目录路径
78 以 name + id + .jpg 或 以 id + .jpg 为文件名
79 有可能无相片
80
81 :param personal: 字典类型,封装着个人具体信息
82 :param binary: 二进制数据
83 :return: 无
84 """
85 if binary != ‘‘:
86 file_path = ‘E:/Baihe/1/‘ if personal[‘gender‘] == "1" else ‘E:/Baihe/0/‘ #
87 if not os.path.exists(file_path): # 如果该路径不存在
88 os.makedirs(file_path) # 创建该路径
89 try:
90 # 向file_path路径保存图片
91 with open(file_path + personal[‘nickname‘] + str(personal[‘userID‘]) + ‘.jpg‘,‘wb‘) as file:
92 file.write(binary)
93 except OSError:
94 with open(file_path + str(personal[‘userID‘]) + ‘.jpg‘,‘wb‘) as file:
95 file.write(binary)
96
97
98 def no_exact_division(miss_id_list):
99 """
100 当包含用户id的列表长度不能被8整除且列表长度小于8时调用该方法
101
102 :param miss_id_list: 为列表类型,封装着用户id
103 :return: 无
104 """
105 miss_info_lists = ba.get_miss_info(miss_id_list) # 获取列表的个人信息
106 personal_data(miss_info_lists) # 遍历一组的信息
107
108
109 class Baihe(object):
110
111 def __init__(self,account,password):
112 """
113 初始化
114 :param account: 账号
115 :param password: 密码
116 """
117 self.is_begin = True # 开始爬取数据
118 self.index = 0 # 控制self.info长度为8个
119 self.info = [] # 临时保存用户id
120 self.page = 29 # 页码
121 self.account = account # 账号
122 self.password = password # 密码
123 self.req = requests.session() # 会话,保证Cookie一致
124
125 def login(self):
126 """
127 登录
128
129 :return: 无
130 """
131 # 登录的url
132 url_login = ‘http://my.baihe.com/Getinterlogin/gotoLogin?event=3&spmp=4.20.87.225.1049&‘ 133 ‘txtLoginEMail={}&txtLoginPwd={}‘.format(self.account,self.password)
134 login_dict = {}
135 try:
136 # 向服务器发送get请求
137 login_dict = self.req.get(url_login,headers=HEADERS,proxies={"http": HTTP_IP_PROXIES_1},timeout=500).json()
138 except requests.exceptions.ProxyError: # 代理网络连接慢或无网络
139 time.sleep(5)
140 # 递归调用self.login()
141 self.login()
142 time.sleep(3)
143 print(‘login: ‘,login_dict)
144 self.req.keep_alive = False # 关闭会话多余的连接
145 if login_dict[‘data‘] == 1:
146 print(‘登录成功‘)
147 else:
148 print(‘登录失败, 30分钟以后自动登录。。。。。。。。‘)
149 time.sleep(1800)
150 # 递归调用self.login()
151 self.login()
152 print(‘login is cookie ‘, requests.utils.dict_from_cookiejar(self.req.cookies)) # 查看登录后的会话cookie
153
154 def filtrate_miss(self,pages):
155 """
156 根据条件筛选数据,不提供条件参数
157
158 :param pages: 页码。该网站只提供62页的数据
159 :return: 包含160个用户的id的列表
160 """
161 time.sleep(2)
162 # 获取用户id的url
163 url_miss = ‘http://search.baihe.com/Search/getUserID‘
164 # from表单数据
165 params_miss = {"minAge": 18, "maxAge": 85, "minHeight": 144, "maxHeight": 210, "education": ‘1-8‘,
166 "income": ‘1-12‘, "city": -1, "hasPhoto": 1, "page": pages, "sorterField": 1}
167 miss_dict = {}
168 try:
169 # 发送post请求
170 miss_dict = self.req.post(url_miss,data=params_miss,headers=HEADERS,proxies={‘http‘:HTTP_IP_PROXIES_2}).json()
171 except requests.exceptions.ProxyError: # 代理网络连接慢或无网络
172 time.sleep(5)
173 # 递归调用self.filtrate_miss()
174 self.filtrate_miss(pages)
175 time.sleep(2)
176 print(‘miss is cookies ‘, requests.utils.dict_from_cookiejar(self.req.cookies)) # 查看筛选后的会话cookie
177 print(‘miss dict: ‘,miss_dict)
178 print(len(miss_dict[‘data‘]),‘个‘)
179 return miss_dict[‘data‘]
180
181 def get_miss_info(self,infos):
182 """
183 获取用户详细信息
184
185 :param infos: 列表类型,封装着个人id,可能为一组(8),或小于8个
186 :return: 包含一组的详细信息
187 """
188 if len(infos) == FING_INDEX: # infos列表长度等于8时
189 url_info = ‘http://search.baihe.com/search/getUserList?userIDs={},{},{},{},{},{},{},{}‘190 .format(infos[0],infos[1],infos[2],infos[3],infos[4],infos[5],infos[6],infos[7])
191 else: # infos列表长度小于8时
192 bracket = ‘‘ # 参数userIDs的值
193 for lens in range(len(infos)):
194 bracket += (str(infos[lens]) + ‘,‘) # 构造该表示:"{},{},{},{},{},{},{},{},"
195 # 获取用户详细信息的url bracket[:len(bracket)-1]: 分片,干掉最后一个“,”
196 url_info = ‘http://search.baihe.com/search/getUserList?userIDs=‘ + bracket[:len(bracket)-1]
197 miss_info = {}
198 try:
199 # 发送post请求
200 miss_info = self.req.post(url_info,headers=HEADERS,proxies={‘http‘:HTTP_IP_PROXIES_2}).json()
201 except requests.exceptions.ProxyError: # 代理网络连接慢或无网络
202 time.sleep(5)
203 # 递归调用self.get_miss_info()
204 self.get_miss_info(infos)
205 time.sleep(2)
206 return miss_info[‘data‘]
207
208 def exact_division(self,miss_id_list):
209 """
210 当包含用户id的列表长度能被8整除或包含用户id的列表长度不能被8整除且包含用户id的列表长度大于8
211
212 :param miss_id_list: id信息列表(160)
213 :return: 无
214 """
215 for user_id in miss_id_list:
216 self.index += 1
217 self.info.append(user_id)
218 if ba.index == FING_INDEX:
219 print(‘user id: ‘, self.info)
220 miss_info_list = ba.get_miss_info(self.info) # 8
221 if None != miss_info_list:
222 # 使self.index,self.info为初值,以便8人一组
223 self.index = 0
224 self.info = []
225 print(‘miss info list: ‘, miss_info_list)
226 personal_data(miss_info_list) # 遍历一组(8)的信息
227 else:
228 print(‘miss info list is null‘)
229 continue
230
231 def main(self):
232 """
233 具体实施
234
235 :return: 无
236 """
237 self.login() # 登录
238 while self.is_begin: # 开始
239 print(‘正在获取‘,self.page,‘页.......‘)
240 miss_id_list = self.filtrate_miss(self.page) # 获取用户id列表
241 if len(miss_id_list) != 0: # 列表有id
242 num = len(miss_id_list) % FING_INDEX # 模运算
243 if num == 0: # 被8整除
244 self.exact_division(miss_id_list)
245 else: # 没有被8整除 , 虽然该分支没有执行,但还是要加上。因为该网站总是提供160个id
246 print(‘余数: ‘,num)
247 if len(miss_id_list) > FING_INDEX: # id列表的长度大于8
248 copy_miss_id_list = miss_id_list[:len(miss_id_list) - num] # 分片 取8个一组
249 self.exact_division(copy_miss_id_list)
250 no_exact_division(miss_id_list[len(miss_id_list) - num:]) # 余下的个人信息
251 else:
252 no_exact_division(miss_id_list) # 小于8个人的个人的信息
253 else:
254 print(‘数据已爬完。。。。。‘)
255 self.is_begin = False
256 self.page += 1
257 time.sleep(10)
258 # 运行
259 if __name__ == ‘__main__‘:
260 ba = Baihe(‘xxxxxxxxx‘, ‘xxxxxxxxx‘) # 账号 密码
261 ba.main()
温馨提示:想爬女的,就找个性别为男的账号。想爬男的,就找个性别为女的账号。