Python 3 爬虫-爬取我的博客园的所有博文列表

描述

该链接爬取的是作者在CSDN上写的博文,我就研究爬取一下我自己在博客园上的博文吧。
这是我的博客园首页:http://www.cnblogs.com/wsygdb/default.html

确定要提取的信息:
1.标题
2.发布日期
3.文章链接
4.浏览量
5.评论量

确认headers

使用fiddler来查看访问我的博客园首页所需的报头:

确认报头为:

headers = {
    'Host': 'www.cnblogs.com',
    'Connection': 'keep-alive',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9'
}

分析网页源代码

获取网页源代码

根据url和伪装的header获取网页源代码

def getHtml(url,headers):
    request = urllib.request.Request(url=url,headers=headers)
    page = urllib.request.urlopen(request)
    html = page.read()
    return html

调用时,报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

我怀疑是不是程序获取的页面源码是经过压缩的,添加解压过程:
解压

def ungzip(data):
    try:
        print('正在解压...')
        data = gzip.decompress(data)
        print('解压完成')
    except:
        print('未压缩,无需解压')
    return data

OK,问题完美解决

提取博文信息

博文需要提取两个信息:

  1. 文章链接、文章标题、发布时间、阅读数和评论数;
  2. “下一页”的链接;

获取文章链接、文章标题、发布时间、阅读数和评论数

如图,这是一篇文章的相关数据:

			<div class="postTitle">
				<a id="homepage1_HomePageDays_DaysList_ctl06_DayList_TitleUrl_0" class="postTitle2" href="http://www.cnblogs.com/wsygdb/p/7661220.html">解决:Invalid character found in the request target.The valid characters are defined in RFC 7230 and RFC3986</a>
			</div>
			<div class="postCon"><div class="c_b_p_desc">摘要: [toc] 背景 在将tomcat升级到7.0.81版后,发现系统的有些功能不能使用了,查询日志发现是有些地址直接被tomcat认为存在不合法字符,返回HTTP 400错误响应,错入信息如下: 原因分析 经了解,这个问题是高版本tomcat中的新特性:就是严格按照 RFC 3986规范进行访问解析,<a href="http://www.cnblogs.com/wsygdb/p/7661220.html" class="c_b_p_desc_readmore">阅读全文</a></div></div>
			<div class="clear"></div>
			<div class="postDesc">posted @ 2017-10-13 14:59 我是一个豆笔 阅读(62) 评论(0)  <a href ="https://i.cnblogs.com/EditPosts.aspx?postid=7661220" rel="nofollow">编辑</a></div>
			<div class="clear"></div>

获取文章的相关信息的正则表达式:文章链接、文章标题、发布时间、阅读数和评论数
articleInfoRe = r'class="postTitle2".href="(.?)">(.?).?@.(.?).我是一个豆笔.?阅读((.?)).?评论((.?))'

获取“下一页”的链接

如图,这是“下一页”的页面源代码数据:

<div class="topicListFooter"><div id="nav_next_page"><a href="http://www.cnblogs.com/wsygdb/default.html?page=2">下一页</a></div></div>

对应的正则表达式为:
isNextPage = r'href="(.*?)">下一页'

此处对正则表达式做一个简要说明:
1).
? 是一个固定的搭配,.和代表可以匹配任意无限多个字符,加上?表示使用非贪婪模式进行匹配,也就是我们会尽可能短地做匹配,以后我们还会大量用到 .? 的搭配。
2)(.?)代表一个分组,在这个正则表达式中我们匹配了1个分组,在后面的遍历item中,item[0]就代表第一个(.?)所指代的内容,item[1]就代表第二个(.?)所指代的内容,以此类推。

获取我的博客园的所有文章数据

获取规则:
分页获取我的博客园的所有的文章链接、文章标题、发布时间、阅读数和点赞数。
匹配该页是否还有下一页,若有则继续获取下一页的数据,直到最后一页。

这是整个程序代码:

'''
描述:博客园的文章列表爬虫(http://www.cnblogs.com/wsygdb/default.html),获取每篇文章的标题、发布日期、文章链接、浏览量和评论量。
时间:2017.11.28
作者:我是一个豆笔
'''

import urllib.request,sys,gzip,re
print(sys.getdefaultencoding())

headers = {
    'Host': 'www.cnblogs.com',
    'Connection': 'keep-alive',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9'
}

# 判断是否还有下一页
isNextPage = r'href="(.*?)">下一页</a></div></div>'

# 获取文章的相关信息的正则表达式链接、文章标题、发布时间、阅读数和评论数
articleInfoRe = r'class="postTitle2".href="(.*?)">(.*?)</a>.*?@.(.*?).我是一个豆笔.*?阅读((.*?)).*?评论((.*?))'

url = 'http://www.cnblogs.com/wsygdb/default.html'

# 根据url和伪装的header获取网页源代码
def getHtml(url,headers):
    request = urllib.request.Request(url=url,headers=headers)
    page = urllib.request.urlopen(request)
    html = page.read()
    return html

# 解压
def ungzip(data):
    try:
        print('正在解压...')
        data = gzip.decompress(data)
        print('解压完成')
    except:
        print('未压缩,无需解压')
    return data

html = getHtml(url,headers)
data = ungzip(html).decode('utf-8')
# print(data)

allArticleInfo = []

while True:
    # 获取当前页列表
    articleInfoCom = re.compile(articleInfoRe, re.S)  # 由于有换行的情况,使用DOTALL模式匹配
    articleInfos = re.findall(articleInfoCom, data)
    for articleInfo in articleInfos:
        allArticleInfo.append(articleInfo)

    # 按照是否有“下一页”来判断是否获获取完了所有页
    isNextPageCom = re.compile(isNextPage) 
    nextPages = re.findall(isNextPageCom, data)
    if len(nextPages)>=1:
        nextPage = nextPages[0]
        print(nextPage)
        if nextPage != "":
            url = nextPage
            html = getHtml(url, headers)
            data = ungzip(html).decode('utf-8')
            continue
        else:
            break
    else:
        break

# 循环输出
for articleInfo in allArticleInfo:
    print(articleInfo)

原文地址:https://www.cnblogs.com/wsygdb/p/7942982.html