Python高级应用程序设计任务,,Python高级应用


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 = 121         # 要获取的url22         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             # 通过正则匹配的title31             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 = 137 38             print(‘当前总页数:%s‘ % total_page)39             # 判断有多少页,若返回的信息是下一页就设置为1,否则就用抓取到的页数40             if total_page == ‘下一页‘:41                 total_page = 142             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然后拼接成url79     def run(self):80         while True:81             code = self.r.lpop(‘h_code‘)82 83             if code is None:84                 print("当前url请求结束!")85                 break86 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         # 要获取的url102         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 WordCloud160 import matplotlib.pyplot as plt161 import jieba162 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 pymysql199 import matplotlib.pyplot as plt200 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, redis230 231 # 连接数据库232 def my_db(table_name):233     import pymysql234     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_name242     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_code257 258 # 将code的值添加到缓存里259 def add_redis(comments_code):260     r = redis.Redis(host=‘127.0.0.1‘, password=‘‘, db=0)  # 端口号默认6379261     for data in comments_code:262         r.lpush(‘h_code‘, data["cid"])263     print(‘添加完毕!‘)264 265 # 从缓存里面获取code266 def get_redis():267     r = redis.Redis(host=‘127.0.0.1‘, password=‘‘, db=0)  # 端口号默认6379268     r.lpop(‘h_code‘)269 270 # 删除code271 def del_redis():272     r = redis.Redis(host=‘127.0.0.1‘, password=‘‘, db=0)  # 端口号默认6379273     r.delete(‘h_code‘)274     print("key删除成功!")275277 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高级应用程序设计任务

评论关闭