网页新闻抓取(免费下载!华为云2021应用构建技术实践(图))
优采云 发布时间: 2021-12-24 16:11网页新闻抓取(免费下载!华为云2021应用构建技术实践(图))
免费下载!华为云2021应用建设技术实践合集,年度干货>>>
我们之前实现的新闻爬虫运行后很快就可以爬取大量的新闻网页。数据库中存储的网页的html代码并不是我们想要的最终结果。最终的结果应该是结构化的数据,至少包括url、标题、发布时间、正文内容、来源网站等。
因此,爬虫不仅要做下载的工作,还要做数据清洗和提取的工作。所以,写爬虫是综合能力的体现。
一个典型的新闻页面包括几个不同的区域:
我们要提取的新闻元素收录在:
导航栏区域和相关链接区域的文字不属于新闻元素。
新闻的标题、发布时间、正文内容一般都是从我们抓取的html中提取出来的。如果只是网站的一个新闻页面,提取这三个内容很简单,写三个正则表达式就可以完美提取。但是,我们的爬虫抓取了数百个 网站 网页。为这么多不同格式的网页编写正则表达式会很累,一旦网页稍作修改,表达式可能会失效,维护这组表达式也很累。
当然,穷尽的方法我们想不通,还得探索一个好的算法来实现。
1. 标题提取
基本上,标题会出现在html标签中,但会附加频道名称、网站名称等信息;
标题也会出现在网页的“标题区”中。
那么这两个地方哪里比较容易提取标题呢?
网页的“标题区”没有明显的标记,不同网站的“标题区”的html代码部分差别很大。所以这个区域不容易提取。
然后就只剩下标签了。这个标签很容易提取,无论是正则表达式还是lxml解析。频道名称、网站名称等信息如何去除,并不容易。
我们先来看看,标签中的附加信息是:
观察这些标题,不难发现新闻标题、频道名称、网站名称之间有一些连接符号。然后我可以通过这些连接器拆分标题,并找出最长的部分是新闻标题。
这个想法也很容易实现。这里就不写代码了,留给小猿作为思考练习自己去实现。
2. 发布时间提取
发布时间是指这个网页在这个网站上上线的时间,一般会出现在文本标题下——元数据区。从html代码来看,这块区域并没有什么特别的地方可供我们定位,尤其是在很多网站板子面前,几乎不可能定位到这个区域。这就需要我们另辟蹊径。
就像标题一样,我们来看看一些网站发布时间是怎么写的:
这些写在网页上的发布时间都有一个共同的特点,就是一个代表时间、年、月、日、时、分、秒的字符串,无非就是这些元素。通过正则表达式,我们列举了一些不同时间表达式的正则表达式(也就是几个),然后我们就可以从网页文本中匹配提取发布时间。
这也是一个很容易实现的想法,但是细节比较多,应该尽量覆盖表达。写出这样的函数来提取发布时间并不是那么容易的。小猴子们充分发挥自己的动手能力,看看能写出什么样的函数实现。这也是对小猿的一种锻炼。
3. 文本提取
正文(包括新闻图片)是新闻网页的主体部分,在视觉上占据中间位置,是新闻内容的主要文本区域。提取文本的方法有很多种,实现复杂或简单。本文介绍的方法是基于老猿猴多年实践经验和思考的一种简单快捷的方法。我们称之为“节点文本密度方法”。
我们知道,一个网页的html代码是由不同的标签(tags)组成的树状结构树,每个标签都是树的一个节点。通过遍历这个树结构的每个节点,找到文本最多的节点,就是文本所在的节点。按照这个思路,我们来实现代码。
3.1 实现源码
<p>#!/usr/bin/env python3
#File: maincontent.py
#Author: veelion
import re
import time
import traceback
import cchardet
import lxml
import lxml.html
from lxml.html import HtmlComment
REGEXES = {
'okMaybeItsACandidateRe': re.compile(
'and|article|artical|body|column|main|shadow', re.I),
'positiveRe': re.compile(
('article|arti|body|content|entry|hentry|main|page|'
'artical|zoom|arti|context|message|editor|'
'pagination|post|txt|text|blog|story'), re.I),
'negativeRe': re.compile(
('copyright|combx|comment||contact|foot|footer|footnote|decl|copy|'
'notice|'
'masthead|media|meta|outbrain|promo|related|scroll|link|pagebottom|bottom|'
'other|shoutbox|sidebar|sponsor|shopping|tags|tool|widget'), re.I),
}
class MainContent:
def __init__(self,):
self.non_content_tag = set([
'head',
'meta',
'script',
'style',
'object', 'embed',
'iframe',
'marquee',
'select',
])
self.title = ''
self.p_space = re.compile(r'\s')
self.p_html = re.compile(r'