Python高级应用程序设计任务要求

Posted 牛牛k

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python高级应用程序设计任务要求相关的知识,希望对你有一定的参考价值。

一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称
网易云歌手信息
2.主题式网络爬虫爬取的内容与数据特征分析
内容:
网易云的各类歌手信息
数据特征:
歌手名,关注数,动态,粉丝数
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
分析获取所有歌手的方法,从以下的地址请求方式可以看出id跟initail的数字存在规律

 

 因此定义变量如下

二、主题页面的结构特征分析(15分)
1.主题页面的结构特征
具有不同类型的歌手的页面,需要做动态爬取

2.Htmls页面解析
地址的变化

 

 

歌手家路径地址的获取 

 

 

歌手信息内容

 

 


3.节点(标签)查找方法与遍历方法
(必要时画出节点树结构)
使用类选择器找到对应的标签,然后进行地址拼接
eg:家目录地址:
soup.select(\'a.nm.nm-icn.f-thide.s-fc0~a\')
 在歌手家目录中找到歌手名称:
soup.select(\'#j-name-wrap > span.tit.f-ff2.s-fc0.f-thide\')[0].string

三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
代码:
  1 # coding:utf-8
  2 import hashlib
  3 import requests
  4 import chardet
  5 from bs4 import BeautifulSoup
  6 from selenium import webdriver
  7 import re
  8 import pymysql as ps
  9 import pandas as pd
 10 import matplotlib.pyplot as plt
 11 import numpy as np
 12 
 13 class FormHotspot(object):
 14     def __init__(self):
 15         self.new_craw_url = set()
 16         self.old_craw_url = set()
 17         self.url_size = 0
 18         # 无头启动 selenium
 19         opt = webdriver.chrome.options.Options()
 20         opt.set_headless()
 21         self.browser = webdriver.Chrome(chrome_options=opt)
 22         self.host = \'localhost\'
 23         self.user = \'root\'
 24         self.password = \'\'
 25         self.database = \'wyy\'
 26         self.con = None
 27         self.curs = None
 28 
 29     \'\'\'
 30     爬取
 31     \'\'\'
 32     def craw(self):
 33         # ------------------------- 歌手地址爬取部分 ---------------------
 34         # 歌手分类跟排列下载
 35         classification = [1001, 1002, 1003, 2001, 2002, 2003, 6001, 6002, 6003, 7001, 7002, 7003, 4001, 4002, 4003]  # id的值
 36         arrange = [-1, 0, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,89, 90]  # initial的值
 37         #classification = [1001, 1002]  # id的值
 38         #arrange = [-1, 0]  # initial的值
 39         self.url_size = int(input("请爬取您想要爬取的歌手的个数:"))
 40         print("温馨提示 !  歌手信息太多情耐心等待! …… ……")
 41         #爬取歌手加路径地址
 42         for c in classification:
 43             for a in arrange:
 44                 if (self.new_craw_url_size() == self.url_size):
 45                     break
 46                 url = \'https://music.163.com/discover/artist/cat?id=\' + str(c) + \'&initial=\' + str(a)
 47                 downSongList = self.down_song_list(url)
 48                 # 解析歌手列表
 49                 songList = self.parser_song_list(downSongList)
 50                 # 增加新的地址
 51                 for new_url in songList:
 52                     self.add_new_craw_url(new_url)
 53         # ------------------------ 歌手详情部分 -------------------------
 54         oldSize = self.new_craw_url_size()
 55         #爬取歌手信息
 56         print("》》》预计有%s个歌手待爬取" % oldSize)
 57         success = 0
 58         while (self.has_new_craw_url()):
 59             try:
 60                 # -----------下载
 61                 new_url = self.get_new_craw_url()
 62                 print("--------------歌手详情地址:"+new_url+":开始爬取")
 63                 songHtml = self.down_song(new_url)
 64                 # -----------解析
 65                 data = self.parser_song(songHtml)
 66                 # -----------保存
 67                 success = success + self.keep_song(data)
 68             except:
 69                 print("操作歌手出现错误出错")
 70         # 展示
 71         print("》》》%s个歌手信息爬取失败!" % (oldSize - success))
 72         print("》》》%s个歌手信息爬取成功!" % success)
 73         df = self.get_song()
 74 
 75         # 当前歌手信息对照表
 76         print("*************************************************")
 77         print("*************当前歌手id-name对照表****************")
 78         print(df[[\'id\',\'name\']])
 79         self.show_song(df)
 80 
 81     \'\'\'
 82     ----------------------- 歌手详情页 start -----------------------------
 83     \'\'\'
 84     \'\'\'
 85     歌手信息下载
 86     \'\'\'
 87     def down_song(self,url):
 88         try:
 89             if url is None:
 90                 return None
 91             s = requests.session()
 92             header = {
 93                 \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\',
 94                 "Referer": "https://music.163.com/"
 95             }
 96             self.browser.get(url)
 97             self.browser.switch_to.frame(\'g_iframe\')
 98             html = self.browser.page_source
 99             return html
100         except:
101             print("----------------down song failed--------------")
102             return None
103 
104     \'\'\'
105     歌手信息解析
106     \'\'\'
107     def parser_song(self,html):
108         if html is None:
109             return None
110         soup = BeautifulSoup(html,"html.parser")
111         # 歌手名称
112         name = soup.select(\'#j-name-wrap > span.tit.f-ff2.s-fc0.f-thide\')[0].string
113         # 动态
114         dynamic = soup.select(\'#event_count\')[0].string
115         # 关注
116         follow = soup.select(\'#follow_count\')[0].string
117         # 粉丝
118         fans = soup.select(\'#fan_count\')[0].string
119         return {\'name\':name, \'dynamic\':dynamic, \'follow\':follow, \'fans\':fans}
120 
121     \'\'\'
122     歌手信息保存
123     \'\'\'
124     def keep_song(self,data):
125         try:
126             self.open_mysql()
127             sql = "insert into singer (name,dynamic,follow,fans) values (%s,%s,%s,%s)"
128             params = (data[\'name\'],data[\'dynamic\'],data[\'follow\'],data[\'fans\'])
129             row = self.curs.execute(sql, params)
130             self.con.commit()
131             self.close_mysql()
132             return row
133         except:
134             print("插入data:%s \\n失败!"%data)
135             self.con.rollback()
136             self.close_mysql()
137             return 0
138 
139     \'\'\'
140     歌手信息获取
141     \'\'\'
142     def get_song(self):
143         self.open_mysql()
144         sql = sql = "select * from singer order by id asc"
145         try:
146             df = pd.read_sql(sql=sql,con=self.con)
147             self.close_mysql()
148             return df
149         except:
150             print(\'获取数据失败!\')
151             self.close_mysql()
152             return None
153 
154     \'\'\'
155     歌手信息显示
156     \'\'\'
157     def show_song(self,data):
158         id = data[\'id\']
159         dynamic = data[\'dynamic\']
160         follow = data[\'follow\']
161         fans = data[\'fans\']
162         # x轴刻度最小值
163         xmin = (id[id.idxmin()] - 1)
164         xmax = (id[id.idxmax()] + 1)
165         # 设置坐标轴刻度
166         my_x_ticks = np.arange(xmin, xmax, 1)
167         plt.figure()
168         # 显示中文标签
169         plt.rcParams[\'font.sans-serif\'] = [\'SimHei\']
170         # -------------------- 子图 ------------------------
171         axes1 = plt.subplot(2,2,1) #子图
172         plt.scatter(id, dynamic)
173         # 设置坐标轴范围
174         plt.xlim((xmin,xmax))
175         plt.xticks(my_x_ticks)
176         plt.xlabel("歌手id")
177         plt.ylabel("动态")
178         plt.grid()
179         plt.title("网易云歌手 动态")
180         axes2 = plt.subplot(2, 2, 2)
181         plt.scatter(id, follow)
182         # 设置坐标轴范围
183         plt.xlim((xmin, xmax))
184         plt.xticks(my_x_ticks)
185         plt.xlabel("歌手id")
186         plt.ylabel("关注")
187         plt.grid()
188         plt.title("网易云歌手 关注")
189         axes3 = plt.subplot(2, 1, 2)
190         plt.scatter(id, fans)
191         # 设置坐标轴范围
192         plt.xlim((xmin, xmax))
193         plt.xticks(my_x_ticks)
194         plt.xlabel("歌手id")
195         plt.ylabel("粉丝")
196         plt.grid()
197         plt.title("网易云歌手 粉丝")
198         plt.show()
199 
200     \'\'\'
201     正则表达式匹配整数
202     \'\'\'
203     def parser_int_and_str(self,str):
204         pattern = re.compile(r\'[\\d]+\')  # 查找正数字
205         result = pattern.findall(str)
206         return result
207 
208     \'\'\'
209     拼接成日期
210     \'\'\'
211     def to_data(self,data):
212         if data is None:
213             return None
214         result = \'\'
215         # 列表生成式
216         b = [str(i) for i in data]
217         result = "-".join(b)
218         return result
219 
220     \'\'\'
221     拼接标签
222     \'\'\'
223     def to_lable(self,data):
224         if data is None:
225             return None
226         result = \'\'
227         # 列表生成式
228         b = [str(i) for i in data]
229         result = "/".join(b)
230         return result
231 
232     \'\'\'
233         ----------------------- 歌手详情页 end -----------------------------
234         ----------------------- 歌手列表 start -----------------------------
235     \'\'\'
236 
237     \'\'\'
238     歌手列表下载
239     \'\'\'
240     def down_song_list(self, url):
241         try:
242             if url is None:
243                 return None
244             s = requests.session()
245             headers = {
246                 \'accept\':\'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\',
247                 \'accept-encoding\':\'gzip, deflate, br\',
248                 \'accept-language\':\'zh-CN,zh;q=0.9\',
249                 \'cookie\':r\'_ntes_nnid=6d65167963a7e0c4b0a1136906089c4f,1565780034826; _ntes_nuid=6d65167963a7e0c4b0a1136906089c4f; _iuqxldmzr_=32; WM_TID=2AHnJpF%2Bn2pABQBVAFMpvLV1ePTi2O4q; WM_NI=5BWTbk0awQMfZS94LRLtLiRv%2F8uZfsP2oiDvuxpeBVvhfjZiA4itz5bZiRRJ3xGBkB7BC6hnA7lo2yhQKwyVYIx6A%2BkpcmiKpC9wQ7lPEbYvvG6a6S3LkOY2J0g4YU8NQXo%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6ee93b23a91aba183f17baaef8ba6d54a828e9eaef27b9489ba88c65487ab9c82ca2af0fea7c3b92af79e99b5e161f4bfb9b2d06e9a8df7d5cf5a90ac848ad17eede8bbbbe57994eea18ac77eb7a8c086c15eb6b8aa8bd96383eca795f93fa286a7b3d142f1a889a3ea4af59e8dd7eb6683e9a490b173ac8f8598fc5e9b97b8d7c421a9b0ad8eec41b49df798d43db0908b83dc7eb699fa82b559f194a5b0dc3a8af0a9d5dc5ffc929fb9ee37e2a3; JSESSIONID-WYYY=jwTw1lhoqU9W7H05vPDhC3WQ6vZMwl8KkUsb9Jj4%5CMWKsr2GZulWhYFEskvQyvTIEC4lk%2FAogIWPmzGweqBNKQNYvetHSW8f4K50UXbz2DEigwprCqy%2BCn8IGivydVy67%2BuO9U5eUSJc4CkiCwAu5o8gAPWvjdZtDQEuPRm%2BvZhKU1Ua%3A1575468859151\',
250                 \'referer\':\'https://music.163.com/\',
251                 \'user-agent\':\'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\'
252             }
253             self.browser.get(url)
254             self.browser.switch_to.frame(\'g_iframe\')
255             html = self.browser.page_source
256             return html
257         except:
258             print("----------------down 歌手 分类 排序 页面 failed--------------")
259             return None
260 
261 
262     \'\'\'
263     解析歌手列表
264     \'\'\'
265     def parser_song_list(self, cont):
266         try:
267             if cont is None:
268                 return None
269             soup = BeautifulSoup(cont, "html.parser")
270             new_urls = set()
271             # print(soup.prettify())
272             # print(soup.select(\'a.nm.nm-icn.f-thide.s-fc0~a\'))
273             # 便利具有艺术家家目录的a标签的信息
274             for artist in soup.select(\'a.nm.nm-icn.f-thide.s-fc0~a\'):
275                 homeUrl = "https://music.163.com/" + artist[\'href\']
276                 if(not((self.new_craw_url_size()+len(new_urls)) >= self.url_size)):
277                     new_urls.add(homeUrl)
278             return new_urls
279         except:
280             print("---------------------parser 歌手家目录地址 failed--------------------")
281 
282     \'\'\'
283         ----------------------- 歌手列表 end -----------------------------
284     \'\'\'
285 
286     \'\'\'
287     ----------------------- 地址管理 start ---------------------------------
288     增加一个待爬取的地址
289     \'\'\'
290     def add_new_craw_url(self, url):
291         if url is None:
292             return
293         if url not in self.new_craw_url and url not in self.old_craw_url:
294             self.new_craw_url.add(url)
295 
296 
297     \'\'\'
298     获取一个待爬取地址
299     \'\'\'
300     def get_new_craw_url(self):
301         if self.has_new_craw_url():
302             new_craw_url = self.new_craw_url.pop()
303             self.old_craw_url.add(new_craw_url)
304             return new_craw_url
305         else:
306             return None
307 
308 
309     \'\'\'
310     在新地址集合中是否有待爬取地址
311     \'\'\'
312     def has_new_craw_url(self):
313         return self.new_craw_url_size() != 0
314 
315 
316     \'\'\'
317     未爬取的地址的数量
318     \'\'\'
319     def new_craw_url_size(self):
320         return len(self.new_craw_url)
321 
322 
323     \'\'\'
324     被加密数据的长度不管为多少,经过md5加密后得到的16进制的数据,它的长度是固定为32的。
325     \'\'\'
326     def encryption_md5(self, data, password):
327         """
328         由于hash不处理unicode编码的字符串(python3默认字符串是unicode)
329         所以这里判断是否字符串,如果是则进行转码
330         初始化md5、将url进行加密、然后返回加密字串
331         """
332         # 创建md5对象
333         m = hashlib.md5()
334         b = data.encode(encoding=\'utf-8\')
335         m.update(b)
336         return m.hexdigest()
337 
Python高级应用程序设计任务要求

Python高级应用程序设计任务要求

Python高级应用程序设计任务要求

Python高级应用程序设计任务要求

Python高级应用程序设计任务要求

Python高级应用程序设计任务要求