一、背景:
因为另一项目新闻管理系统的需要,以及作为熟悉python基础的练手项目,现准备用python写一个网易新闻爬虫,为新闻管理系统项目获取新闻内容,以解决新闻源的自动获取、添加到数据库的问题。
二、目标:
实现自动化获取网易新闻不同类别的新闻列表url,然后分别爬取新闻内容并存入新闻管理系统项目的mysql数据库,以供新闻管理系统的使用。
三、参考:
因为对python的爬虫和html解析模块不是很了解,因此在写的过程中查阅参考了许多模块的教程和资料。另外对于html页面中的标签正则,经查阅后使用断言以解决。
具体的爬虫结构,链接和正文内容的解析与正则模式、数据存储表均为自己设计。
参考资料:
- 编写简单的网络爬虫 (python3.2)
http://blog.csdn.net/database_zbye/article/details/38826893 - Python requests模块学习笔记
http://www.cnblogs.com/tangdongchu/p/4229049.html - 采用beautifulsoup库 解析html页面
http://blog.csdn.net/weiyuanke/article/details/16986639 - 《零基础学python》(第二版)»第七章 保存数据 »MySQL数据库(2)
http://docs.pythontab.com/learnpython/231/ - 正则表达式分组、断言详解
http://www.cnblogs.com/iyangyuan/archive/2013/05/30/3107390.html
四、分析:
(一)、新闻爬虫业务流程分析:
- 爬取新闻列表的html页面,解析出新闻的url,存入队列。
- 从队列中取出一个url,爬取新闻内容的html页面,进行解析,将解析出的标题、正文、来源、时间、图片等结果放入数据库。
(二)、实现过程中几个细节分析:
1. 模块的选择和列表页面的爬取:
在看了一些入门文章后,开始打算使用requests模块爬取新闻列表和正文页面,然后使用BeautifulSoup加lxml对页面进行解析,在对网易新闻列表的加载方式经过一番研究后,通过浏览器的开发者工具提取到动态JS加载的新闻标题列表的JSON页面的链接,用手工提取不同分类的JSON链接地址,然后通过requests模块来获取页面。
2. 提取新闻url:
对于列表地址的解析,因为没有了解过JSON数据的处理方式,为了方便起见使用了断言式正则规则来提取出新闻的url。
3. 将url存入队列
为了标识已经访问过的新闻链接,防止程序突然崩溃导致的队列数据丢失和简单的链接去重。使用数据库作为存放新闻页面链接的队列,titles表结构如下:
字段名称 | 数据类型 | Key | Default | 解释 |
---|---|---|---|---|
url | varchar(100) | PRI | NULL | 存放新闻url |
category | varchar(10) | NULL | 存放分类信息 | |
flag | tinyint(4) | NULL | 标记是否获取过内容 |
将url设置为主键,并且在存入新闻链接时使用insert ignore into ...
语句来保证url不会重复,在新插入url的同时将flag设置为0,表示该页面待爬取。
在存入解析完的新闻数据的同时,将titles表中,相对应的url的flag设置为1,表示已经爬取过该页面。
4. 获取新闻界面
同第一步中获取新闻列表界面一样,直接使用requests模块获取页面。因此直接调用其函数。
5. 解析新闻界面
对于新闻内容的提取用到了BeautifulSoup
模块和正则表达式混合进行解析。另外因为网易新闻有些html样式不统一,此处解析只针对占主流的页面样式,对于无法解析的页面进行提示并标记。
另外因为考虑到新闻管理系统需要取出新闻正文,再输出到html界面进行展示,因此对新闻正文的html标签没有使用正则去除、而是原样式保存到数据库。
6. 将解析出的数据存入数据库,同时对已获取内容的url标记
将成功解析的数据存入news表
中,并将titles表
相对应的url的flag设置为1,表示已经获取过该新闻内容。此处遇到过正文、来源等数据长度超过数据库的表字段长度,导致程序中断的问题,对此解决方法是在执行该插入操作时捕获异常,然后对该新闻的url进行flag标记设置为2,跳过此新闻的获取。
将内容格式无法解析的url的flag设置为2,表示已经试图爬取过该页面内容,但是无法获取该新闻。
news表结构如下:
字段名称 | 数据类型 | Key | Default | 解释 |
---|---|---|---|---|
newsId | bigint(20) | PRI | NULL | 新闻ID |
title | varchar(40) | NULL | 标题 | |
content | text | NULL | 正文 | |
imageUrl | varchar(180) | NULL | 首个图片地址(做封面) | |
date | timestamp | CURRENT_TIMESTAMP | 日期 | |
source | varchar(50) | NULL | 来源 | |
clickTraffic | bigint(20) | 0 | 点击量 | |
category | varchar(10) | NULL | 分类 |
五、开发:
(一)、开发环境及工具配置:
开发环境:windows10
开发语言:python3.5
开发工具:IDEL、MySql5.7
使用模块:BeautifulSoup、requests、lxml、pymysql
(二)、建表语句:
title表:
create table titles(
url varchar(100) primary key,
category varchar(10),
flag tinyint not null default 0
);
news表:
create table news(
newsId bigint primary key auto_increment,
title varchar(40),
content text,
imageUrl varchar(180),
date timestamp,
source varchar(50),
clickTraffic bigint default 0,
category varchar(10)
);
(三)、源码:
|
六、测试:
(一)、本地运行测试:
- 运行环境:win10、python3.5
- 运行效果:
成功添加新闻和此次获取数目统计
对无法解析的页面将flag设置为2,跳过
(二)、服务器定时运行测试:
运行环境:centos6.5、python3.5
每小时定时运行设置:
通过linux自带定时运行服务crontab进行设置,每小时自动运行。[root@iZm5e19ccp2hp43c52aze2Z ~]# crontab -l#!/bin/sh0 */1 * * * /usr/local/python3/bin/python3 /usr/local/news.py运行效果:
因定时运行服务不在控制台输出信息,效果可从网站前台页面查看:http://115.28.137.1:8080/,每个小时整点与网易新闻同步更新。七、工作评价:
此次开发为首次接触爬虫、也是首次实现完整的python程序,因此在爬虫结构设计、代码的实现上显得不够简洁、扩展性较差,对于细节的处理不够到位,对于另外一种新闻正文的页面形式没有进行解析而是直接跳过(此页面下多为自媒体投稿,新闻质量较差,所以没有考虑另外解析)。
每日新闻数据量较少、并且在使用的过程中没有出现反爬虫等情况,因此没有考虑多线程和使用代理IP优化。
因为对java的jdbc较为熟悉,所以在使用pymysql对数据库操作时比较顺利。
总的来说,此次项目仅为熟悉python的练手项目,并且项目目的只为了在自己的项目中使用,所以只做了主要功能的实现。