码迷,mamicode.com
首页 > 编程语言 > 详细

Python高级应用程序设计任务

时间:2019-12-20 01:05:30      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:fetch   none   port   commit   rank   int   mic   sub   odi   

 

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

用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)

一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称

穷游网香港旅游攻略中的景点爬取

2.主题式网络爬虫爬取的内容与数据特征分析

内容:主要爬取穷游网香港旅游攻略景点排名前100的旅游景点的信息,以及对应的景点评论信息。

数据特征分析:对所有的评论做了词云、对景点的评分做了可视化和柱状图

3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)

实现思路:首先通过分析此网站得知数据的传输通过ajax实现,其中景点信息固定url为“https://place.qyer.com/poi.php?action=list_json”,通过修改data参数实现翻页。创建一个ScenicInfo 类定义param_info和insert实现对数据的抓取和保存。景点评论信息是通过url拼接来实现,创建一个Comments类定义param_comments发起请求获得json数据,insert方法插入数据库

技术难点:在爬取过程中没有出现反爬。

二、主题页面的结构特征分析(15分)
1.主题页面的结构特征

每页15项数据,爬取了64页,一共960项数据。通过chrome抓包调试发现所有得数据都是通过ajax动态发送只需修改post参数几个。

技术图片

技术图片

2.Htmls页面解析

红框中的数据为爬取字段

技术图片

三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
1.数据爬取与采集

1、景点信息的采集与爬取

 1 # 景点信息的采集与爬取
 2 import pymysql
 3 import requests
 4 
 5 # 定义类名和设置默认参数
 6 class ScenicInfo(object):
 7     def __init__(self):
 8         # 要获取的url
 9         self.url = https://place.qyer.com/poi.php?action=list_json
10         # 设置请求头
11         self.headers = {
12             user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36,
13             referer: https://place.qyer.com/hong-kong/sight/
14         }
15     # 对数据进行清洗和处理
16     def param_info(self, form_data):
17         # 通过request发起请求
18         resp = requests.post(self.url, form_data, headers=self.headers)
19         # 获得返回json数据解析
20         data = resp.json()[data][list]
21         # 遍历返回的数据,将数据插入数据库
22         for index in data:
23             print(index[id], index[cnname], index[rank], index[grade], index[url], index[commentCount])
24             # 执行操作数据库的方法
25             self.insert(index[id], index[cnname], index[rank], index[grade], index[url],
26                         index[commentCount])
27 
28     def run(self):
29         # 通过遍历来改变post的参数,来实现翻页
30         for page in range(1, 65):
31             print(当前正在采集第%s页! % str(page))
32             form_data = {
33                 page: page,
34                 type: city,
35                 pid: 50,
36                 sort: 32,
37                 subsort: all,
38                 isnominate: -1,
39                 haslastm: false,
40                 rank: 6,
41             }
42             # 将带着参数传入这个方法,然后发起请求
43             self.param_info(form_data)
44     # 数据持久化
45     def insert(*details):
46         # 连接数据库
47         db = pymysql.connect("localhost", "root", "root", "honk")
48         # 获得游标
49         cursor = db.cursor()
50         # 设置sql语句
51         sql = "insert into scenic (cid,name,rank,grade,url,comment_count)value(%s,%s,%s,%s,%s,%s)"
52         # 执行sql语句
53         try:
54             cursor.execute(sql, details)
55             db.commit()
56             print(插入数据成功)
57         except Exception as e:
58             db.rollback()
59             print("插入数据失败", e)
60         db.close()
61 
62 if __name__ == __main__:
63     scenicInfo = ScenicInfo()
64     scenicInfo.run()

 

2、景点评论信息的采集与爬取

 1 # 景点评论的采集和爬取
 2 import re
 3 
 4 import redis
 5 import requests
 6 
 7 import pymysql
 8 from redis import StrictRedis
 9 
10 # 定义类名和设置默认参数
11 class Comments(object):
12     def __init__(self):
13         self.r = StrictRedis(host=localhost, port=6379, db=0, decode_responses=True)
14         # 设置请求头
15         self.headers = {
16             user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
17         }
18     # 获取评论信息
19     def param_comments(self, code):
20         page = 1
21         # 要获取的url
22         url = https://place.qyer.com/poi.php?action=comment&page={}&order=5&poiid={}&starLevel=all.format(page, code)
23         print(url)
24         # 通过request发起请求
25         resp = requests.post(url, headers=self.headers)
26         # 获得返回json数据分析
27         data = resp.json()[data][lists]
28         # 判断数据是否为空
29         if len(data) != 0:
30             # 通过正则匹配的title
31             try:
32                 total = resp.json()[data][pagehtml]
33                 total_page = re.findall(title="(.*?)", total)[0].replace(..., ‘‘)
34 
35             except Exception as e:
36                 total_page = 1
37 
38             print(当前总页数:%s % total_page)
39             # 判断有多少页,若返回的信息是下一页就设置为1,否则就用抓取到的页数
40             if total_page == 下一页:
41                 total_page = 1
42             for page in range(1, int(total_page) + 1):
43                 print("当前总共%s页,正在采集第%s页!" % (total_page, page))
44                 # 对数据进行清洗和处理
45                 url = https://place.qyer.com/poi.php?action=comment&page={}&order=5&poiid={}&starLevel=all.format(
46                     page,
47                     code)
48                 # 通过request发起请求
49                 resp = requests.post(url, headers=self.headers)
50                 # 获得返回json数据分析
51                 data = resp.json()[data][lists]
52                 # 遍历返回的数据,将数据插入数据库
53                 for index in data:
54                     name = index[userinfo][name]
55                     starlevel = index[starlevel]
56                     content = index[content]
57                     date = index[date]
58                     print(code, name, starlevel, content, date)
59                     # 将带着参数传入这个方法,然后发起请求
60                     self.insert(code, name, starlevel, content, date)
61     # 数据持久化
62     def insert(self, *details):
63         # 连接数据库
64         db = pymysql.connect("localhost", "root", "root", "honk")
65         # 获得游标
66         cursor = db.cursor()
67         # 设置sql语句
68         sql = "insert into comments (sid,name,starlevel,content,date)value(%s,%s,%s,%s,%s)"
69         # 执行sql语句
70         try:
71             cursor.execute(sql, details)
72             db.commit()
73             print(插入数据成功)
74         except Exception as e:
75             db.rollback()
76             print("插入数据失败", e)
77         db.close()
78     # 设置死循环,从缓存里面拿到景点的code然后拼接成url
79     def run(self):
80         while True:
81             code = self.r.lpop(h_code)
82 
83             if code is None:
84                 print("当前url请求结束!")
85                 break
86 
87             self.param_comments(code)
88 
89 
90 if __name__ == __main__:
91     comments = Comments()
92     comments.run()

技术图片

2.对数据进行清洗和处理

1、对景点信息数据进行清洗和处理

技术图片

2、对景点评论数据进行清洗和处理

技术图片

3.文本分析(可选):jieba分词、wordcloud可视化

 1 from wordcloud import WordCloud
 2 import matplotlib.pyplot as plt
 3 import jieba
 4 
 5 # 生成词云
 6 def create_word_cloud(filename):
 7     text = open("{}.txt".format(filename), encoding=utf-8).read()
 8     # 结巴分词
 9     wordlist = jieba.cut(text, cut_all=True)
10     wl = " ".join(wordlist)
11 
12     # 设置词云
13     wc = WordCloud(
14         # 设置背景颜色
15         background_color="white",
16         # 设置最大显示的词云数
17         max_words=2000,
18         # 这种字体都在电脑字体中,一般路径
19         font_path=C:\Windows\Fonts\simfang.ttf,
20         height=1200,
21         width=1600,
22         # 设置字体最大值
23         max_font_size=100,
24         # 设置有多少种随机生成状态,即有多少种配色方案
25         random_state=30,
26     )
27 
28     myword = wc.generate(wl)  # 生成词云
29     # 展示词云图
30     plt.imshow(myword)
31     plt.axis("off")
32     plt.show()
33     wc.to_file(comments.png)  # 把词云保存下来
34 
35 if __name__ == __main__:
36     create_word_cloud(comments)

技术图片

技术图片

4.数据分析与可视化
(例如:数据柱形图、直方图、散点图、盒图、分布图、数据回归分析等)

 1 import pymysql
 2 import matplotlib.pyplot as plt
 3 
 4 db = pymysql.connect(host="localhost", user=root, passwd="root", port=3306, db="honk", charset=utf8)
 5 cursor = db.cursor()  # 获取一个游标
 6 sql = "select name,grade from scenic"
 7 cursor.execute(sql)
 8 result = cursor.fetchall()  # result为元组
 9 
10 # 将元组数据存进列表中
11 city = []
12 need = []
13 for x in result:
14     city.append(x[0])
15     need.append(float(x[1]))
16 
17 # 直方图
18 plt.bar(range(len(need)), need, color=steelblue, tick_label=city)
19 plt.xlabel("景点")
20 plt.ylabel("评分")
21 plt.title("城市职位需求图")
22 for x, y in enumerate(need):
23     plt.text(x - 2, y + 2, %s % y)
24 plt.show()
25 cursor.close()  # 关闭游标
26 db.close()  # 关闭数据库

技术图片

技术图片
5.数据持久化

1、景点信息数据持久化

技术图片

2、景点评论信息数据持久化

技术图片

技术图片

6.附完整程序代码

  1 # 景点评论的采集和爬取
  2 import re
  3 
  4 import redis
  5 import requests
  6 
  7 import pymysql
  8 from redis import StrictRedis
  9 
 10 # 定义类名和设置默认参数
 11 class Comments(object):
 12     def __init__(self):
 13         self.r = StrictRedis(host=localhost, port=6379, db=0, decode_responses=True)
 14         # 设置请求头
 15         self.headers = {
 16             user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
 17         }
 18     # 获取评论信息
 19     def param_comments(self, code):
 20         page = 1
 21         # 要获取的url
 22         url = https://place.qyer.com/poi.php?action=comment&page={}&order=5&poiid={}&starLevel=all.format(page, code)
 23         print(url)
 24         # 通过request发起请求
 25         resp = requests.post(url, headers=self.headers)
 26         # 获得返回json数据分析
 27         data = resp.json()[data][lists]
 28         # 判断数据是否为空
 29         if len(data) != 0:
 30             # 通过正则匹配的title
 31             try:
 32                 total = resp.json()[data][pagehtml]
 33                 total_page = re.findall(title="(.*?)", total)[0].replace(..., ‘‘)
 34 
 35             except Exception as e:
 36                 total_page = 1
 37 
 38             print(当前总页数:%s % total_page)
 39             # 判断有多少页,若返回的信息是下一页就设置为1,否则就用抓取到的页数
 40             if total_page == 下一页:
 41                 total_page = 1
 42             for page in range(1, int(total_page) + 1):
 43                 print("当前总共%s页,正在采集第%s页!" % (total_page, page))
 44                 # 对数据进行清洗和处理
 45                 url = https://place.qyer.com/poi.php?action=comment&page={}&order=5&poiid={}&starLevel=all.format(
 46                     page,
 47                     code)
 48                 # 通过request发起请求
 49                 resp = requests.post(url, headers=self.headers)
 50                 # 获得返回json数据分析
 51                 data = resp.json()[data][lists]
 52                 # 遍历返回的数据,将数据插入数据库
 53                 for index in data:
 54                     name = index[userinfo][name]
 55                     starlevel = index[starlevel]
 56                     content = index[content]
 57                     date = index[date]
 58                     print(code, name, starlevel, content, date)
 59                     # 将带着参数传入这个方法,然后发起请求
 60                     self.insert(code, name, starlevel, content, date)
 61     # 数据持久化
 62     def insert(self, *details):
 63         # 连接数据库
 64         db = pymysql.connect("localhost", "root", "root", "honk")
 65         # 获得游标
 66         cursor = db.cursor()
 67         # 设置sql语句
 68         sql = "insert into comments (sid,name,starlevel,content,date)value(%s,%s,%s,%s,%s)"
 69         # 执行sql语句
 70         try:
 71             cursor.execute(sql, details)
 72             db.commit()
 73             print(插入数据成功)
 74         except Exception as e:
 75             db.rollback()
 76             print("插入数据失败", e)
 77         db.close()
 78     # 设置死循环,从缓存里面拿到景点的code然后拼接成url
 79     def run(self):
 80         while True:
 81             code = self.r.lpop(h_code)
 82 
 83             if code is None:
 84                 print("当前url请求结束!")
 85                 break
 86 
 87             self.param_comments(code)
 88 
 90 if __name__ == __main__:
 91     comments = Comments()
 92     comments.run()
 93 
 94 # 景点信息的采集与爬取
 95 import pymysql
 96 import requests
 97 
 98 # 定义类名和设置默认参数
 99 class ScenicInfo(object):
100     def __init__(self):
101         # 要获取的url
102         self.url = https://place.qyer.com/poi.php?action=list_json
103         # 设置请求头
104         self.headers = {
105             user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36,
106             referer: https://place.qyer.com/hong-kong/sight/
107         }
108     # 对数据进行清洗和处理
109     def param_info(self, form_data):
110         # 通过request发起请求
111         resp = requests.post(self.url, form_data, headers=self.headers)
112         # 获得返回json数据解析
113         data = resp.json()[data][list]
114         # 遍历返回的数据,将数据插入数据库
115         for index in data:
116             print(index[id], index[cnname], index[rank], index[grade], index[url], index[commentCount])
117             # 执行操作数据库的方法
118             self.insert(index[id], index[cnname], index[rank], index[grade], index[url],
119                         index[commentCount])
120 
121     def run(self):
122         # 通过遍历来改变post的参数,来实现翻页
123         for page in range(1, 65):
124             print(当前正在采集第%s页! % str(page))
125             form_data = {
126                 page: page,
127                 type: city,
128                 pid: 50,
129                 sort: 32,
130                 subsort: all,
131                 isnominate: -1,
132                 haslastm: false,
133                 rank: 6,
134             }
135             # 将带着参数传入这个方法,然后发起请求
136             self.param_info(form_data)
137     # 数据持久化
138     def insert(*details):
139         # 连接数据库
140         db = pymysql.connect("localhost", "root", "root", "honk")
141         # 获得游标
142         cursor = db.cursor()
143         # 设置sql语句
144         sql = "insert into scenic (cid,name,rank,grade,url,comment_count)value(%s,%s,%s,%s,%s,%s)"
145         # 执行sql语句
146         try:
147             cursor.execute(sql, details)
148             db.commit()
149             print(插入数据成功)
150         except Exception as e:
151             db.rollback()
152             print("插入数据失败", e)
153         db.close()
154 
155 if __name__ == __main__:
156     scenicInfo = ScenicInfo()
157     scenicInfo.run()
158 
159 from wordcloud import WordCloud
160 import matplotlib.pyplot as plt
161 import jieba
162 
163 # 生成词云
164 def create_word_cloud(filename):
165     text = open("{}.txt".format(filename), encoding=utf-8).read()
166     # 结巴分词
167     wordlist = jieba.cut(text, cut_all=True)
168     wl = " ".join(wordlist)
169 
170     # 设置词云
171     wc = WordCloud(
172         # 设置背景颜色
173         background_color="white",
174         # 设置最大显示的词云数
175         max_words=2000,
176         # 这种字体都在电脑字体中,一般路径
177         font_path=C:\Windows\Fonts\simfang.ttf,
178         height=1200,
179         width=1600,
180         # 设置字体最大值
181         max_font_size=100,
182         # 设置有多少种随机生成状态,即有多少种配色方案
183         random_state=30,
184     )
185     # 生成词云
186     myword = wc.generate(wl)
187     # 展示词云图
188     plt.imshow(myword)
189     plt.axis("off")
190     plt.show()
191     # 把词云保存下来
192     wc.to_file(comments.png)
193 
194 if __name__ == __main__:
195     create_word_cloud(comments)
196 
198 import pymysql
199 import matplotlib.pyplot as plt
200 
201 db = pymysql.connect(host="localhost", user=root, passwd="root", port=3306, db="honk", charset=utf8)
202 # 获取一个游标
203 cursor = db.cursor()
204 sql = "select name,grade from scenic"
205 cursor.execute(sql)
206 # result为元组
207 result = cursor.fetchall()
208 
209 # 将元组数据存进列表中
210 city = []
211 need = []
212 for x in result:
213     city.append(x[0])
214     need.append(float(x[1]))
215 
216 # 直方图
217 plt.bar(range(len(need)), need, color=steelblue, tick_label=city)
218 plt.xlabel("景点")
219 plt.ylabel("评分")
220 plt.title("城市职位需求图")
221 for x, y in enumerate(need):
222     plt.text(x - 2, y + 2, %s % y)
223 plt.show()
224 # 关闭游标
225 cursor.close()
226 # 关闭数据库
227 db.close()
228 
229 import json, redis
230 
231 # 连接数据库
232 def my_db(table_name):
233     import pymysql
234     coon = pymysql.connect(
235         user=root, passwd=root, host=127.0.0.1, port=3306,
236         db=honk, charset=utf8
237     )
238     # 建立游标,指定cursor类型返回的是字典
239     cur = coon.cursor(cursor=pymysql.cursors.DictCursor)
240     # cur = coon.cursor()
241     sql = select cid from %s ; % table_name
242     data = cur.execute(sql)
243     # 关闭数据库连接
244     cur.close()
245     coon.close()
246     return cur.fetchall()
247 
248 # 对景点urlcode进行去重
249 def removal_set(all_date):
250     comments_code = set()
251     for date in all_date:
252         print(date)
253         key = date.get(sid)
254         comments_code.add(key)
255         print(key)
256     return comments_code
257 
258 # 将code的值添加到缓存里
259 def add_redis(comments_code):
260     r = redis.Redis(host=127.0.0.1, password=‘‘, db=0)  # 端口号默认6379
261     for data in comments_code:
262         r.lpush(h_code, data["cid"])
263     print(添加完毕!)
264 
265 # 从缓存里面获取code
266 def get_redis():
267     r = redis.Redis(host=127.0.0.1, password=‘‘, db=0)  # 端口号默认6379
268     r.lpop(h_code)
269 
270 # 删除code
271 def del_redis():
272     r = redis.Redis(host=127.0.0.1, password=‘‘, db=0)  # 端口号默认6379
273     r.delete(h_code)
274     print("key删除成功!")
275
277 if __name__ == __main__:
278     all_data = my_db(scenic)
279 
280     # comments_code = removal_set(all_data)
281 
282     add_redis(all_data)
283     # del_redis()
284     # get_redis()

四、结论(10分)
1.经过对主题数据的分析与可视化,可以得到哪些结论?

1、太平山的景点综合排名为第一名

2、多数人来香港都会到维多利亚港、太平山和海洋公园

3、来香港旅游的人还是很多的。

2.对本次程序设计任务完成的情况做一个简单的小结。

答:这次的程序设计任务对我来说是一个新的挑战也是一项难度较高的任务,从原有的课本到书店查看相关书籍到关于python语言和网络爬虫的网课学习 ,由最开始的编程小白渐渐地学会了如何去写代码如何去一步步解决问题。最开始一直害怕的是网站反爬问题,不过幸好后来没有遇到这个问题。历时一个多月我终于完成了这份艰巨的任务,这次的挑战,让我学习和看到了新的不一样的东西,收获了许多新的知识。希望自己以后能够继续进步继续努力。

 

Python高级应用程序设计任务

标签:fetch   none   port   commit   rank   int   mic   sub   odi   

原文地址:https://www.cnblogs.com/ll55/p/12057621.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!