爬取全本小说并保存到本地!
尊重知识产权,建议阅读原版 本文章仅作示例,请勿用作非法用途
该系列的其他篇目:
效果
如你所见,这是一个完整的小说文档。尽管小说原网站并没有提供下载功能,但我们爬虫却做到了!那么,让我们开始吧~
开始
这篇小说从哪里来?互联网上。我们不妨先去看看网页端效果是怎样的。
打开这个网页,你就会看到完整的章节列表、广告和广告……
让我们随便打开一章,右键——查看源代码,看看这些东西背后到底是什么。
哇,真的是非常的amazing啊,我们居然一下就找到了我们所需要的小说内容!
但是兄弟,我们怎么才能获得这些源码呢?
走,我们进入下一步!
获取网页源码
上节课 (没看过的请自行查看) 我们讲过,urllib的urlopen函数可以打开一个网页链接,这一次咱们如法炮制,再试一次。
def get_html(url):
response = ur.urlopen(url)
html = response.read().decode("utf-8")
return html
然而当你print一下之后,你会发现:
print(get_html(URL))
纳尼?403 Forbidden?服务器把我们拒绝了!
没错,有些服务器因为不希望过多的机器访问造成过大的服务器压力,于是会对爬虫采取拒绝访问的措施。你可能就要问了:为什么他会知道我是一只爬虫而不是正常访问呢?
事实上,当访问上述链接时,我们的请求头会有一个User-Agent告诉服务器我们是谁。比如说当我们使用浏览器访问时,就会有如下UA:
而当使用urllib时,默认的UA是:
毫无疑问,服务器一看到它,就把我们bang了……
但方法总比问题多,这个UA事实上是完全可以更换的。于是我们改一改:
def get_html(url):
head = { # 创造请求头
"Referer": url,
"User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
}
request = ur.Request(url, headers=head)# 新建一个request,使用我们构造好的head
response = ur.urlopen(request)# 访问
html = response.read().decode("utf-8")
return html
你是否发现了一个问题:这一次我们的urlopen改为了打开request而不是url直链。我们来看看文档是怎么说的:
urlopen(url, data=None, timeout=<object object at 0x00634920>, *, cafile=None, capath=None, cadefault=False, context=None) Open the URL url, which can be either a string or a Request object.
事实上,当你使用字符串作为参数时,python会自动帮你利用url和默认的数据构造一个Request再完成访问。
那么结果如何呢?我们再跑一次:
当当当当!搞定~
提取内容
有了网页,提取内容就不是什么问题了。通过观察我们可以知道,所有小说内容包裹在<div id="content">后面。于是,利用正则表达式 【正则表达式是一种根据特定规则提取文本的技术,您可以先学习之后再回到本章节观看】 ,我们可以写出如下代码:
re_content = re.compile(r'''<div id="content">\n(.*)''', re.M)
content = re.findall(re_content, html)[0]
再处理一下特殊字符,让文本好看一点,我们最终得到了这样一个函数:
def get_base_content(html):
re_content = re.compile(r'''<div id="content">\n(.*)''', re.M)
content = re.findall(re_content, html)[0]
content = content.replace("<br />", "\n")
content = content.replace(" \n", "")
return content
完美!
获取标题
如法炮制,我们把标题也取一下,看着好看一点:
def get_title(html):
re_title = re.compile(r'<meta name="keywords" content="(.*),神澜奇域海龙珠,唐家三少,E8中文网" />')
return re.search(re_title, html).group(1)
这样就完成了一章内容的获取。
批量爬取
爬完了一章,批量爬取就很简单了。
观察源代码,我们可以看到所有的下一章链接都被明显标出
所以事实上,我们要做的就是:
那么如何判断是不是最后一章呢?我们看一下网页是怎么处理的:
可以看到,网页版对于最后一张的处理是回到主页。所以我们只需要判断获取到的下一页url是不是一个 ./ 就可以确定了。
上述完整代码如下:
BASE_URL = "https://www.e8zw.com/book/416/416756/"
def get_next_page(html):
re_next_page = re.compile(r'<a id="pager_next" href="(.*?)"')
return BASE_URL + re.search(re_next_page, html).group(1)
if __name__ == '__main__':
# print(get_base_content(get_html(URL)))
html = ""
url = URL
while True:
html = get_html(url)
text = get_base_content(html)
title = get_title(html)
print(f"{title}\n{text}")
url = get_next_page(html)
保存为文本
读取之后,利用简单的文件操作即可保存啦!
完成,撒花!!!
完整代码
import re
import urllib.request as ur
BASE_URL = "https://www.e8zw.com/book/416/416756/"
URL = "https://www.e8zw.com/book/416/416756/2235794.html"
def get_html(url):
head = { # 创造请求头
"Referer": url,
"User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
}
request = ur.Request(url, headers=head) # 新建一个request,使用我们构造好的head
response = ur.urlopen(request) # 访问
html = response.read().decode("utf-8")
return html
def get_base_content(html):
re_content = re.compile(r'''<div id="content">\n(.*)''', re.M)
content = re.findall(re_content, html)[0]
content = content.replace("<br />", "\n")
content = content.replace(" \n", "")
return content
def get_next_page(html):
re_next_page = re.compile(r'<a id="pager_next" href="(.*?)"')
return BASE_URL + re.search(re_next_page, html).group(1)
def get_title(html):
re_title = re.compile(r'<meta name="keywords" content="(.*),神澜奇域海龙珠,唐家三少,E8中文网" />')
return re.search(re_title, html).group(1)
if __name__ == '__main__':
html = ""
url = URL
f = open("D:/projects/something_download/神澜奇遇——海龙珠.txt", "w+", encoding="utf-8")
while True:
html = get_html(url)
text = get_base_content(html)
title = get_title(html)
print(f"{title}\n{text}")
url = get_next_page(html)
f.write(f"{title}{text}\n\n")
if url.endswith("./"):
print("全本写入完毕!")
break
f.close()
其他
- 你可以试着用这样的方法保存其他小说,然后不出意外,有些地方的小说你一定会遇到问题(譬如访问不了,网页中没有内容等等)。我们之后再扯
- 我的水平不高,所讲之处难免有所漏洞,还望指正
后续
- (2.5)爬取小说另一个例子+GUI界面
- (3)爬取豆瓣书籍列表
- 联系我:github(是的没错,我是个菜鸡)