如何一天做出新闻搜索引擎(1)——新闻的搜集与数据库的建立
新闻的搜集与数据库的建立
- 写在前面
- 1. 爬取什么
- 2. 怎么爬
- 2.1 分析网页的HTML源码,找到规律
- 2.1.1 分析滚动页面
- 2.1.2 分析新闻页面
- 2.2 分析完毕,开始动手写代码爬网页
- 2.2.1 爬滚动页面
- 2.2.2 爬新闻页面
- 3. 爬完干什么
- 3.1 分析新闻内容,提取出有关搜索的关键信息
- 3.2 保存入数据库
- 4. 刷新一下,马上回来
- 写在后面
写在前面
大家好,这一章主要来介绍如何选取爬取的页面,如何确定爬取内容的方法和怎样建立数据库。
如需查看完整源代码,请移步我的github页面,本文所讲内容在Refresh.py
文件里。
其他章节请访问我的这篇博客。
1. 爬取什么
我们选取页面的原则是页面要尽可能地“整齐”。什么是“整齐”呢,请看下面两图:
其中图一是新浪新闻的首页,图二是新浪新闻的滚动页面。显然从视觉直观来说,图二比图一更为地整齐。
为什么我们要选择比较整齐地页面进行爬取呢?原因在于这种页面的HTML代码也比较地有规律,爬网页的时候也更为地省心。比如图二的每一则新闻的代码都是这样的:
所以我们只要在爬取的过程中,找到每个c_tit类下的href就可以找到每条新闻对应的网页地址了。
2. 怎么爬
(大家可以参考网易云上的免费视频课程,当时我就是就着这个视频学的,虽然视频中的爬取方法因为新浪新闻网页架构的更改失效了,但可以从中学到网络爬虫的基本方法)
2.1 分析网页的HTML源码,找到规律
2.1.1 分析滚动页面
我们使用google的chrome浏览器进行分析。在chrome浏览器中搜索“新浪新闻”,点击进入新浪新闻主页。也就是这样:
然后点击左上角的“滚动”(图中用红圈标出的地方),进入滚动页面。
之后我们进入开发者模式。如下图所示,点击“开发者工具”:
然后按下图的步骤点击:
(由于上一条新闻《27岁未婚女孩…》太过惊悚,我们选一个温和点的)
然后就出现了下图:
图中被选中的代码就是我们想从这个页面上提取的信息(即每条新闻的网址)。
只要知道每条新闻的网址,然后我们再访问每条新闻的页面,提取出关于该新闻的信息即可。
所以接下来我们进入这条新闻的页面,找出新闻页面的HTML代码规律。
2.1.2 分析新闻页面
我们要找的信息:新闻的标题、日期、正文和关键字。
按照之前的套路,我们打开开发者工具,并找到正文的位置:
标题、日期以及关键字的寻找方法请看下文。
明确了这些,接下来我们就可以开始动手爬新闻了。?
2.2 分析完毕,开始动手写代码爬网页
2.2.1 爬滚动页面
经过一番寻找与尝试(具体尝试的步骤请在上文所列出的视频教程中查看,说实话,当初尝试了挺久才碰巧找到的),我发现在Source中有一个feed啥的比较关键:
请注意红下划线的地方。我们发现地址可以拼接成:
https://feed.mix.sina.com.cn/api/roll/get?pageid=153&lid=2509&k=&num=50&page=%d
的形式。其中%d可以代入数字,表示第几页的滚动页面。
后面的r=0.02768994656458923&callback=jQuery1112035449799366314805_1550924012864&_=1550924012872
与页面的实时刷新有关,我们不去管他。
然后我们编写代码去访问这个地址:(其中maxPage是我设定的滚动页面的最大页码)
for page in range(1,maxPage+1):url = 'https://feed.mix.sina.com.cn/api/roll/get?pageid=153&lid=2509&k=&num=50&page=%d'%(page)try:res = requests.get(url)except:continue
注意try – except,因为可能有些网页是无法访问的,为了提高容错性,我们加一个try–except,如果访问错误则忽略,直接访问下一页滚动页面。
如果成功访问,我们得到的res就是一个response对象,然后对这个response对象进行处理。
把它丢进BeautifulSoup中进行解析:(BeautifulSoup是一个从HTML或XML文件中提取出数据的Python库,简单来说,他可以将文件中的标签整理成树状结构,方便查阅和应用。不了解的读者请自行百度或google)
for page in range(1,maxPage+1):url = 'https://feed.mix.sina.com.cn/api/roll/get?pageid=153&lid=2509&k=&num=50&page=%d'%(page)#url = 'https://news.sina.com.cn/roll/#pageid=153&lid=2509&k=&num=50&page=%d'%(page)try:res = requests.get(url)except:continuepageInfo = []res.encoding = 'utf-8'soup = BeautifulSoup(res.text, 'html.parser')jd = json.loads(soup.text)
我们看jd是一个什么东东:
原来jd是一个字典,jd['result']['data']
中的每个元素都是滚动页面中的一则新闻,里面中有很多我们要找的信息:url, title, keywords等。
for page in range(1,maxPage+1):url = 'https://feed.mix.sina.com.cn/api/roll/get?pageid=153&lid=2509&k=&num=50&page=%d'%(page)try:res = requests.get(url)except:continuepageInfo = []res.encoding = 'utf-8'soup = BeautifulSoup(res.text, 'html.parser')jd = json.loads(soup.text)for info in jd['result']['data']:url = info['url']title = info['title']keywords = info['keywords']
2.2.2 爬新闻页面
结束了吗?好像还少了点啥…对,少了时间和最重要的正文。这就要我们从每则新闻的新闻页面中爬取。
在2.2.1中我们已经得到了所有新闻的网页地址(url),我们进入这个编写一个名为getUrlInfo
的函数,提取网页中的各类信息:
def getUrlInfo(url):try:res = requests.get(url)res.encoding = 'utf-8'#print(res.text)soup = BeautifulSoup(res.text, 'html.parser')article = soup.select('.article p')[:-1]article = '\n\t'.join([p.text.strip() for p in article]) #将文章中的每一段用\n\t隔开date = soup.select('.date')[0].textdate = datetime.strptime(date, '%Y年%m月%d日 %H:%M')result = {}result['date'] = dateresult['article'] = articleexcept:return #如果出错,则返回Nonereturn result
然后将date, article 等信息与上文的url, title, keywords合并,并将每则新闻的这些信息提取出来保存在news
字典中,再将每页滚动页面中所有新闻对应的字典插入到pageInfo
的数组中,最后将pageInfo中的信息插入到allPages
数组中:
def dealPages(maxPage):global allPagesallPages = []for page in range(1,maxPage+1):url = 'https://feed.mix.sina.com.cn/api/roll/get?pageid=153&lid=2509&k=&num=50&page=%d'%(page)try:res = requests.get(url)except:continuepageInfo = []res.encoding = 'utf-8'soup = BeautifulSoup(res.text, 'html.parser')jd = json.loads(soup.text)for info in jd['result']['data']:url = info['url']title = info['title']keywords = info['keywords']date_article = getUrlInfo(url)if date_article == None:continuedate = date_article['date']date = date.strftime('%Y-%m-%d %H:%M')article = date_article['article']news = {}news['url'] = urlnews['title'] = titlenews['keywords'] = keywordsnews['date'] = datenews['article'] = articlepageInfo.append(news)allPages.extend(pageInfo)
即
news --- 每条新闻的信息
pageInfo --- 每页滚动页面的信息
allPages --- 所有滚动页面的信息
这样,dealPages和getUrlInfo两个函数双剑合璧,页码为1-maxPage的滚动页面的信息就被我提取出来了。
3. 爬完干什么
3.1 分析新闻内容,提取出有关搜索的关键信息
首先我们要去掉新闻中与搜索无关的词。这里就要引入“停用词”的概念。
比如在一句话中:“小明和小红去北京天安门玩了”,“小红”、“小明”、“北京”、“天安门”都是对于搜索有用的信息,而“和”、“了”这些词就和搜索无关了。这些与搜索无关的词就叫“停用词”。网上有停用词的汇总,本文用的是这一个停用词表。
为了提高搜索速度,我们只针对标题和关键词进行搜索,而关键词中是没有停用词的,所以只需去掉标题中的停用词。
首先我们用jieba
对标题进行分词,然后去除停用词以及标点。将剩下的词连同关键词一起作为搜索的依据。统计每个词出现的频率,计入名为Terms
的字典中,再将每则新闻Terms
字典汇总入Termdict
的list中:
def build_TermDict():global TermDict, N, avg_lglobal allPagesTermDict.clear()avg_l = 0 #文档平均长度,即平均每个新闻中有多少个有效词N = len(allPages)cloudTerm = [] #用于云图构建for doc_id in range(0,N):doc = allPages[doc_id]#toCut = doc['title']*30 + doc['keywords']*15+doc['article'] #设定不同的权重toCut = doc['title']+doc['keywords']terms = jieba.cut_for_search(toCut)ld = 0 #文档长度,即文章中有效词的个数#去除标点和停用词Terms = {}for p in terms:p = p.strip()if len(p)>0 and p not in stop_words and not p.isdigit():if p in Terms:Terms[p] += 1else:Terms[p] = 1cloudTerm.append(p)ld += 1avg_l += 1#将Terms中元素加入TermDictfor p in Terms:if p in TermDict:TermDict[p][0] += Terms[p]else:TermDict[p] = [1,[]]TermDict[p][1].append('%d\t%s\t%d\t%d'%(doc_id, doc['date'], Terms[p],ld ))avg_l /= N#生成云图cloudText = ','.join(cloudTerm)wc = WordCloud(background_color="white", #背景颜色max_words=200, #显示最大词数font_path="simhei.ttf", #使用字体min_font_size=15,max_font_size=50, width=400 #图幅宽度)wc.generate(cloudText)wc.to_file("wordcloud.gif")#将TermDict中文档信息合并成一个字符串,用\n隔开for i in TermDict:TermDict[i][1] = '\n'.join(TermDict[i][1])
ok✌️
3.2 保存入数据库
信息提取完…当然是把数据存到数据库中啊?
数据库的好处在于:每次搜索时不需要重新提取网页中的信息,直接在数据库中查找就ok了。想象一下,如果每次搜索都要等待几分钟让程序爬取网页的信息,这酸爽,不敢相信啊。
在这里我们用sqlite3存储数据,代码如下(如不熟悉sqlite3请自行百度,网上很多讲解的?):
def WriteInDataBase():#将TermDict写入数据库global TermDictdf = pandas.DataFrame(TermDict).Tdb = sqlite3.connect('news.sqlite')df.to_sql('TermDict',con = db,if_exists='replace') #如果表存在就将表替代db.close()#将N 和 avg_l写入txt文件中paraF = open('parameter.txt','w')paraF.write('%d\t%d'%(N,avg_l))paraF.close()#将allPages写入数据库df = pandas.DataFrame(allPages)db = sqlite3.connect('news.sqlite')df.T.to_sql('allPages',con = db,if_exists='replace') #如果表存在就将表替代db.close()
4. 刷新一下,马上回来
到此为止,搜索新闻、处理新闻信息以及建立数据库的工作就完成了,我们最后用一个refresh
函数来将上面写的函数串在一起,完成刷新的工作:
def refresh():global maxPageglobal allPages, TermDict, stop_words, N, avg_l#处理滚动页面allPages = []dealPages(maxPage)#构建列表stop_words,包含停用词和标点stop_words = []build_StopWords()#构建TermDictTermDict={}N = 0avg_l = 0build_TermDict()#将TermDict转化为pandas中的DataFrame,再写入数据库sqliteWriteInDataBase()
小小地测试一下,嗯,不错:
if __name__ == '__main__':refresh()
这样,这一章的任务——新闻的搜集与数据库的建立,就完成了?
写在后面
如需查看完整源代码,请移步我的github页面,本文所讲内容在Refresh.py
文件里。
如有不当,欢迎大神指出!
如何一天做出新闻搜索引擎(1)——新闻的搜集与数据库的建立相关推荐
- 如何一天做出新闻搜索引擎(0)
如何一天做出新闻搜索引擎(0) 写在前面的话 内容与目录 效果展示图 写在后面的话 写在前面的话 大家好!这篇文章主要是记录了我在制作新浪新闻搜索引擎的一些心得与体会.虽然这篇文章的题目叫<如何 ...
- 学工在线新闻搜索引擎0.1 beta版
研究搜索引擎已经有一段时间了.经过半个月的努力,学工在线新闻搜索引擎推出了0.1beta版, 虽然有很多问题和不足,但还是实现了基本的搜索功能. 测试地址:http://202.114.20.55:8 ...
- 基于Python与spimi的新闻搜索引擎设计与实现_kaic
摘 要 在互联网还没有被普及的那个年代,人们查阅资料首先会想到去图书馆,而互联网的诞生,极大便利了人们查询信息的方式,搜索引擎打开了最有效的查询方法大门. 利用Python语言以及相关技术,实现 ...
- Google新闻vs门户新闻:决裂还是共存
"面对Google的新动作,中国门户要么有所创新,奋起直追:要么可以利用政策手段,尽快展开狙击.否则,新浪等门户网站即使不会战败,也会被极大分割市场份额."IT资深评论家方兴东说. ...
- Android 实现用户收藏新闻以及查看新闻(简易新闻 六)
Android 实现用户收藏新闻以及查看新闻(简易新闻 六) 效果图: 因为录制的gif过长无法上传,所以这里分为两段,一段是用户未登录状态下收藏新闻需登录,用户登录后可以收藏: 第二段用户未登录查看 ...
- 抓取全网财经新闻,计算新闻相关股票的多空舆情,量化买入
抓取全网财经新闻,计算新闻相关股票的多空舆情,量化买入 按照新闻的热度(涉及该股票的新闻出现次数)进行排序,买入排名靠前的前5只股票 详细代码和结果 https://uqer.io/community ...
- JavaScript html 图片滑动切换效果,幻灯片式切换,新闻展示,滚动新闻
新闻展示,滚动新闻 程序说明 原理就是通过不断设置滑动对象的left(水平切换)和top(垂直切换)来实现图片切换的动态效果. 首先需要一个容器,程序会自动设置容器overflow为hidden,如果 ...
- 如何使用Java+SSM(Spring+SpringMVC+Mybatis)开发个性化新闻推荐系统 在线新闻推荐系统 基于用户项目协同过滤、内容、聚类、关联规则推荐算法实现WebNewsRSMEx
如何使用Java+SSM(Spring+SpringMVC+Mybatis)开发个性化新闻推荐系统 在线新闻推荐系统 基于用户项目协同过滤.内容.聚类.关联规则推荐算法实现WebNewsRSMEx 一 ...
- 爬取腾讯新闻中省份疫情数据到Mysql数据库
爬取腾讯新闻中省份疫情数据到Mysql数据库 本人是一个中职学生,第一次发表自己所学到技术-- 本篇文章所用到的语言及工具等: python 3.8 pycharm Mysql Navicat Pre ...
- python爬取百度新闻所有的新闻的前1页 标题和URL地址
这是我自己写的一个爬取百度新闻的一个代码,欢迎大家多来讨论,谢谢!(自己已经测试可以使用,在文章最后见效果图) ''' re模板:2.2.1 requests模板:2.18.4 bs4模板:4.6.0 ...
最新文章
- java 32位jdk_jdk9 32位下载 jdk9.0(Java SE Development Kit 9) v9.0.4 官方版 32位 下载-脚本之家...
- 看完微软大神写的求平均值代码,我意识到自己还是 too young 了
- status_code想要得到302却得到200_中考200天倒计时!教你高效规划!抓紧抢报预留座位!...
- linux命令之grep 命令
- easyui datagrid加载数据的三种方式
- Linux的文件传输工具(WinSCP)付下载连接
- native react 常用指令_React Native 常用命令或快捷键合集
- ReactNative调研结果
- python会议室系统预定_会议室预定系统
- Docker系列(八)Docker的CS模式、守护进程的配置和操作
- 14.bash(2) 与 环境变量
- 格而知之8:我所理解的Runtime(3)
- 【Python】numpy矩阵运算大全
- 技术图文:基于“科比投篮”数据集学Pandas
- Datawhale---Task2(EDA-数据探索性分析)
- Python str 模块
- 关于wifi共享大师破解版在电脑休眠后wifi无法连接的问题
- 今天我们谈谈关于java自学的那些事儿(为那些目标模糊的码农们)
- 成功解决android 网络视频边下载变播放。
- Spark数据分析之第4课