目的:爬取豆瓣读书/新书速递这一页下所有的书名、作者、出版社和出版日期,并依据出版的先后时间对书名进行排序
思路分析:首先分析原网页,以某一本书为类,把要爬取内容的父级标签取出来;然后依次对子级标签(书名、作者等)进行正则匹配;得到书名、作者等目标元素存储在dict中,通过循环得到页面所有的目标元素,交给list存储;最后对list进行排序操作
要用到的库
import pysnooper
import requests
import re
-
pysnooper
是一种代码检查工具,可以通过python的pip安装
pip install pysnooper
-
re
是Python内置模块, 提供了 Perl 风格的正则表达式模式
完整代码:
@pysnooper.snoop(output='./log/debug.log')
class Spider():
# 爬取目录地址
url = 'https://book.douban.com/latest?icn=index-latestbook-all'
# 打开浏览器, 直接复制请求报头
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36 Edg/81.0.416.53'
headers = {
'User-Agent': user_agent
}
# 要用到的各种正则表达式作为类属性, 后面会用到
root_pattern = '<div class="detail-frame">([\s\S]*?)</div>'
bn_pattern = '<a[\s\S]*?>([\s\S]*?)</a>'
ed_pattern = '<p class="color-gray">([\s\S]*?)</p>'
da_pattern = '<p class="color-gray">[\s\S]*?(\d{4}-\d{1,2}-?\d?)[\s\S]*?</p>'
'''
@description:爬取网页原始数据
@param {type} 这里说一下,所有类的方法都要传入self参数 {object}
@return: 异常或是原始html页面
'''
def __fetch_content(self):
try:
r = requests.get(self.url, headers=self.headers)
r.raise_for_status() # 请求状态码。 当然这里是多余的,只是记一下,可以通过不同的状态码,抛出不同的异常提示
r.encoding = r.apparent_encoding
return r.text
except Exception as e:
return e
'''
@description: 对请求的网页进行分析处理,这里需要用到上面定义的正则表达式
@param {type} 原始页面数据
@return: 目标信息列表list
'''
def __analysis(self, html):
# root_html为目标元素的父级标签,一本书的所有目标信息都在这个地方
root_html = re.findall(self.root_pattern, html)
authors = []
# 4. 循环得到页面所有书籍的信息
for i in root_html:
book_name = re.findall(self.bn_pattern, i) # 1. 得到书名
editor_name = re.findall(self.ed_pattern, i) # 2. 得到作者/出版信息
date = re.findall(self.da_pattern, i) # 3. 从出版信息中分解出出版日期
# 将一本书的目标信息存储在dict中
author = {'book_name': book_name,'editor_name': editor_name,'date': date}
# 依次将每本书的信息添加到author列表中
authors.append(author)
# 返回书籍信息列表
return authors
'''
@description: 对__analysis返回的信息进一步处理,因为此时得到的数据有很多空白字符(包括换行符),这个方法的目的是把不需要的字符处理成完全干净的字符
@param {type} 经过分析得到的信息列表
@return: 干净的目标信息列表list
'''
def __refine(self, authors):
# lambda匿名函数对authors进行深度处理
l = lambda authors: return {
'book_name': author['book_name'][0],
'editor_name': author['editor_name'][0].strip(),
'date': author['date'][0]
}
# map()函数把authors列表中每一个dict通过匿名函数处理
return map(l, authors)
'''
@description: 返回排序后的信息列表
@param {type} 信息列表
@return: 信息列表
'''
def __sort(self, authors):
return sorted(authors, key=lambda authors: authors['date'])
# 定义排序规则 -- 以出版日期进行排序 图三
def __sort_seed(self, authors):
return authors['date']
# 整理输出列表0
def __show(self, authors):
for i in range(0, len(authors)):
print('出版时间排名第' + str(i + 1) + ':' +
authors[i]['book_name'] + ' ----- ' + authors[i]['editor_name'])
# 除了go方法之外,其他所有的方法都是类的私有方法,不允许外部直接访问,一切数据处理的入口都是go()函数
def go(self):
html = self.__fetch_content()
Message_info = self.__analysis(html)
Message_info = list(self.__refine(Message_info))
Message_info = self.__sort(Message_info)
Message_info = self.__show(Message_info)
print(Message_info)
spider = Spider()
spider.go()
参考文档:
风吟: python之r.raise_for_status() : https: // blog.csdn.net / kangyan_ / article / details / 78506243
python调试利器pysnooper : https: // blog.csdn.net / luanpeng825485697 / article / details / 102954985)
pysnooper github地址 : https: // github.com / cool - RR / pysnooper
网友评论