1.选一个自己感兴趣的主题(所有人不能雷同)。
2.用python 编写爬虫程序,从网络上爬取相关主题的数据。
3.对爬了的数据进行文本分析,生成词云。
4.对文本分析结果进行解释说明。
5.写一篇完整的博客,描述上述实现过程、遇到的问题及解决办法、数据分析思想及结论。
6.最后提交爬取的全部数据、爬虫及数据分析源代码。
1.我选取的是糗事百科里面的 24小时专栏 网址是:https://www.qiushibaike.com/hot/,编译语言是 python,工具是pycharm
2.爬取过程
F12打开开发者工具 找到需要的内容
可以清晰的看到信息都包含在<div class="content-block clearfix"></div> 中所以我们从其中找需要的内容
这里我选取段子内容和up主截图分别如下
这里可以清楚的知道 'up主'信息和'段子内容'都包含在<div id="content-left" class="col1"></div>中
其中‘up主’信息包含在 <h2>标签中,并且包含在<div class="article block untagged mb15 typs_long"></div>中,所以我们获取 'up主'信息的代码可以写为:
1 up = soup.select('#content-left')[0].select('.article')[index].select('.author')[0].select('a')[1].text.strip('\n')
而 '段子内容'包含在<div class="content"></div>的盒子中,并且包含在<div class="article block untagged mb15 typs_long"></div>中,所以我们获取'段子内容'信息的代码可以写为:
content = soup.select('#content-left')[0].select('.article')[index].select('.content')[0].select('span')[0].text.strip('\n')
但是呢,有的用户会以匿名方式发段子(大概害羞吧!!),会出现 一个错误:list out if range,那么该怎么办呢?
答案在最后。
获取完单个需要的信息之后就是获取整页信息,想法是利用for循环获取,因为上述内容都包含在<div class="article block untagged mb15 typs_long"></div>中,代码如下:
1 for content_nums in range(sum_contents): 2 time.sleep(0.2) 3 duanzi_list.append(getContet(url, content_nums))
获取总的内容数目,思路是看HTML代码,发现每个子项目都包含在<div id="content-left" class="col1"></div>中,所以可以得到其长度确定一页的总子项目数目代码如下:
1 def getAllContents(url): 2 # global onePage_AllContents 3 request = requests.get(url) 4 request.encoding = 'utf-8' 5 soup = BeautifulSoup(request.text,'html.parser') 6 7 #一页总内容数 8 onePage_AllContents = soup.select('#content-left')[0].select('.mb15').__len__() 9 return onePage_AllContents
获取完单页,接下来就应该获取所有页面,
1 #获取总页数 2 def getAllPages(url): 3 request = requests.get(url) 4 request.encoding = 'utf-8' 5 soup = BeautifulSoup(request.text,'html.parser') 6 7 number = int(soup.select('.page-numbers')[-1].text) 8 return number
将上述综合起来,写到一个function中,获取所有up主信息和段子内容:
def dict_Contents(url): request = requests.get(url) request.encoding = 'utf-8' soup = BeautifulSoup(request.text, 'html.parser') # time.sleep(1) duanzi_list = [] sum_pages = getAllPages(url) # 总页数 sum_contents = getAllContents(url) for page_nums in range(1, 4): url = 'http://www.qiushibaike.com/hot/page/{0}/'.format(page_nums) time.sleep(1) for content_nums in range(sum_contents): time.sleep(0.2) duanzi_list.append(getContet(url, content_nums)) # for news in duanzi_list: # print(news) return duanzi_list
由于我怕页面未完全加载,可能会出现信息获取错误,就添加一个time.sleep作为延迟,由于页面较多,所以值选取了(1,4)的值。
之后呢,应该生成Excel表,所以利用pandas第三方类库生成Excel表
import pandas df = pandas.DataFrame(list_Allduanzi) df.to_excel('duanzi.xlsx', engine='xlsxwriter')
截图:
将要分词的内容放进duanzi.txt中,代码如下:
1 def writeNewsDetail(content): 2 f = open('duanzi.txt', 'a', encoding='utf-8') 3 f.write(content) 4 f.close()
截图如下:
有了内容之后,接下来就是分词,我分词的类库选择的是jieba分词,是一个比较好的分词,在pycharm中可以直接搜索添加,也可以在命令行中添加 指令是'pip install jieba',但是在命令行中添加需先配置环境变量。那么分词的话,首先,要去掉标点符号。将内容中的标点符号等分隔符全部替换为空格。接着,进行分词切割,(同时我们可以去掉我们不需要的信息放在一个集合里)进行词频统计。并保存在文件中,代码如下:
1 import jieba 2 file = open('duanzi.txt', 'r', encoding='utf-8') 3 duanzi = file.read() 4 file.close() 5 6 sep = '''-/.。""'',!?;:~`·[] \ ,:;“”?!-、}{【】‘’''' 7 exclude = {' ','\ue412','\x01','我','了','的','你','来','我们','被','……','…'} 8 9 for char in sep: 10 duanzi = duanzi.replace(char,'') 11 duanziList = list(jieba.cut(duanzi))#分词 12 duanziDict = {} 13 duanzis = list(set(duanziList)-exclude)#删除非中国汉语字符 14 15 for d in range(0,len(duanzis)): 16 duanziDict[duanzis[d]] = duanzi.count(str(duanzis[d])) 17 18 dictList = list(duanziDict.items()) 19 dictList.sort(key=lambda x:x[1],reverse=True) 20 21 f = open('count.txt','a',encoding='utf-8') 22 for i in range(150): 23 print(dictList[i]) 24 f.write(dictList[i][0] + ':' + str(dictList[i][1]) + '\n') 25 f.close()
截图结果如下:
最后一步就是生成词云了。首先是下载,但是呢在pycharm和命令行下载是行不通的需要通过下载被的文件在使用命令行才行,问题解决有提及。那么代码是:
1 #生成词云 2 from PIL import Image, ImageSequence 3 import numpy as np 4 import matplotlib.pyplot as plt 5 from wordcloud import WordCloud, ImageColorGenerator 6 7 font = r'C:\Windows\Fonts\simhei.TTF' 8 image = Image.open('./qiushibaike.jpg') 9 graph = np.array(image) 10 wc = WordCloud(font_path=font, background_color='White', max_words=50, mask=graph) 11 wc.generate_from_frequencies(duanziciyun) 12 image_color = ImageColorGenerator(graph) 13 plt.imshow(wc) 14 plt.axis("off") 15 plt.show()
词云图片形状是(根据那个糗事百科的背景图):
生成的词云截图如下:
总的代码如下:
1 # -*- coding: UTF-8 -*- 2 import requests 3 import re 4 from bs4 import BeautifulSoup 5 import time 6 import openpyxl 7 import xlsxwriter 8 9 #保存到文本 10 def writeNewsDetail(content): 11 f = open('duanzi.txt', 'a', encoding='utf-8') 12 f.write(content) 13 f.close() 14 15 #获取 16 def getContet(url,index): 17 global up, content 18 request = requests.get(url) 19 request.encoding = 'utf-8' 20 soup = BeautifulSoup(request.text,'html.parser') 21 22 duanzi = {} # 用字典存放信息 23 24 #up主 25 try: 26 up = soup.select('#content-left')[0].select('.article')[index].select('.author')[0].select('a')[1].text.strip('\n') 27 #内容 28 content = soup.select('#content-left')[0].select('.article')[index].select('.content')[0].select('span')[0].text.strip('\n') 29 except IndexError: 30 up = soup.select('#content-left')[0].select('.article')[index].select('.author')[0].select('h2')[0].text.strip('\n') 31 content = soup.select('#content-left')[0].select('.article')[index].select('.content')[0].select('span')[0].text.strip('\n') 32 duanzi['up主'] = up 33 duanzi['段子内容'] = content 34 writeNewsDetail(content) 35 return duanzi 36 37 #获取总页数 38 def getAllPages(url): 39 request = requests.get(url) 40 request.encoding = 'utf-8' 41 soup = BeautifulSoup(request.text,'html.parser') 42 43 number = int(soup.select('.page-numbers')[-1].text) 44 return number 45 46 #获取总的段子数目 47 def getAllContents(url): 48 # global onePage_AllContents 49 request = requests.get(url) 50 request.encoding = 'utf-8' 51 soup = BeautifulSoup(request.text,'html.parser') 52 53 #一页总内容数 54 onePage_AllContents = soup.select('#content-left')[0].select('.mb15').__len__() 55 return onePage_AllContents 56 57 # 将所有段子存放到字典中 58 def dict_Contents(url): 59 request = requests.get(url) 60 request.encoding = 'utf-8' 61 soup = BeautifulSoup(request.text, 'html.parser') 62 # time.sleep(1) 63 duanzi_list = [] 64 sum_pages = getAllPages(url) # 总页数 65 sum_contents = getAllContents(url) 66 for page_nums in range(1, 4): 67 url = 'http://www.qiushibaike.com/hot/page/{0}/'.format(page_nums) 68 time.sleep(1) 69 for content_nums in range(sum_contents): 70 time.sleep(0.2) 71 duanzi_list.append(getContet(url, content_nums)) 72 # for news in duanzi_list: 73 # print(news) 74 return duanzi_list 75 76 77 if __name__ == '__main__': 78 url = 'http://www.qiushibaike.com/hot/' 79 # request = requests.get(url) 80 # request.encoding = 'utf-8' 81 # soup = BeautifulSoup(request.text, 'html.parser') 82 list_Allduanzi = [] 83 list_Allduanzi = dict_Contents(url) 84 #生成excel表 85 import pandas 86 df = pandas.DataFrame(list_Allduanzi) 87 df.to_excel('duanzi.xlsx', engine='xlsxwriter') 88 89 import jieba 90 file = open('duanzi.txt', 'r', encoding='utf-8') 91 duanzi = file.read() 92 file.close() 93 94 sep = '''-/.。""'',!?;:~`·[] \ ,:;“”?!-、}{【】‘’''' 95 exclude = {' ','\ue412','\x01','我','了','的','你','来','我们','被','……','…'} 96 97 for char in sep: 98 duanzi = duanzi.replace(char,'') 99 duanziList = list(jieba.cut(duanzi))#分词 100 duanziDict = {} 101 duanzis = list(set(duanziList)-exclude)#删除非中国汉语字符 102 103 for d in range(0,len(duanzis)): 104 duanziDict[duanzis[d]] = duanzi.count(str(duanzis[d])) 105 106 dictList = list(duanziDict.items()) 107 dictList.sort(key=lambda x:x[1],reverse=True) 108 duanziciyun = {} 109 f = open('count.txt','a',encoding='utf-8') 110 for i in range(150): 111 f.write(dictList[i][0] + ':' + str(dictList[i][1]) + '\n') 112 duanziciyun[dictList[i][0]] = dictList[i][1] 113 f.close() 114 115 #生成词云 116 from PIL import Image, ImageSequence 117 import numpy as np 118 import matplotlib.pyplot as plt 119 from wordcloud import WordCloud, ImageColorGenerator 120 121 font = r'C:\Windows\Fonts\simhei.TTF' 122 image = Image.open('./qiushibaike.jpg') 123 graph = np.array(image) 124 wc = WordCloud(font_path=font, background_color='White', max_words=50, mask=graph) 125 wc.generate_from_frequencies(duanziciyun) 126 image_color = ImageColorGenerator(graph) 127 plt.imshow(wc) 128 plt.axis("off") 129 plt.show()
3.遇到的问题以及解决办法
第一个问题是:上述一开始提及到的,有些up主并非公开的,是匿名用户,它的结构和非匿名用户不一样,那么,我就点击查看,发现只有<span>标签并没<h2>标签,所以我的代码修改如下:
1 #up主 2 try: 3 up = soup.select('#content-left')[0].select('.article')[index].select('.author')[0].select('a')[1].text.strip('\n') 4 #内容 5 content = soup.select('#content-left')[0].select('.article')[index].select('.content')[0].select('span')[0].text.strip('\n') 6 except IndexError: 7 up = soup.select('#content-left')[0].select('.article')[index].select('.author')[0].select('h2')[0].text.strip('\n') 8 content = soup.select('#content-left')[0].select('.article')[index].select('.content')[0].select('span')[0].text.strip('\n')
问题就解决了,其中还学习到了,当 出现错误 'list out of range'时,可以运用try except IndexEorro 处理和寻找问题的根源。
第二个问题是:在利用pandas库生成excel表时,产生了错误 'openpyxl.utils.exceptions.IllegalCharacterError',我解决的办法是在google搜索该问题,然后在stackflow中找到了答案,下载并且导入 ‘import xlsxwriter’ 然后修改导入数据到excel的代码 ‘df.to_excel('duanzi.xlsx', engine='xlsxwriter')’就OK了。
第三个问题是:词云wordcloud载pycharm下载不成功,原因是找不到该文件的详情信息,估计是该工具引进python第三方类库有问题,利用pip进行安装也不成功,那么问题就渐渐浮出水面了,就是匹配不到该文件的版本号,所以,我们需要知道该版本号,上网查了下,因为我的python是3.6版本,所以对应cp36,然后我的是windows系统,所以在LDF中下windows版本的,链接是:https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud,下载amd的,拖入你的python路径中,具体文件目录就自行百度吧(我忘记了!!!)。
我是用anacanda 进行引进该第三方类库的,参考链接:https://www.jianshu.com/p/e4b24a734ccc。
问题大概就这么多了。
4.数据分析思想以及结论
获取段子内容并且进行词频统计,就可以了解现在的人说的是什么梗,或者有什么关键词特别突出即,当你讲笑话或者处于尴尬情况是可以将一两个笑话和谐一下气氛,也可以用这写梗去交朋友或者哄别人开行,(哄女孩子什么的我没说。。哈),总之是很有用的,但是呢,我不晓得为什么生成的都是一个一个词的,并没有很多词组,不知道是不是结巴分词的一个缺点。