从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载

Ehco

5 个月前

本来只是准备做一个爬起点小说名字的爬虫,后来想了一下,为啥不顺便把小说的内容也爬下来呢?于是我就写了这个爬虫,他爬下了各类小说排行榜上的所有章节内容,并保存到本地。仔细想了一下,各种盗版小说阅读器,是不是就是这样做的呢?

目标分析:

首先来看看我们排行榜的地址:

http://www.qu.la/paihangbang/

我们的目的很明确:

找到各类排行旁的的每一部小说的名字,和在该网站的链接:

观察一下网页的结构:

我们很容易就能发现,每一个分类都是包裹在:

<div class="index_toplist mright mbottom">

之中
这种调理清晰的网站,大大方便了我们爬虫的编写

小说标题和链接:

我们在刚才那个div里自己寻找:

<div class="index_toplist mright mbottom">
<div class="toptab" id="top_all_1">
<span>玄幻奇幻排行</span><div>
<div class="topbooks" id="con_o1g_1" style="display: block;">
<ul>
<li><span class="hits">05-06</span><span class="num">1.</span><a href="/book/168/" title="择天记" target="_blank">择天记</a></li><li><span class="hits">05-06</span><span class="num">2.</span><a href="/book/176/" title="大主宰" target="_blank">大主宰</a></li><!--中间省略了不少 --><li><span class="hits">05-06</span><span class="num">3.</span><a href="/book/4140/" title="太古神王" target="_blank">太古神王</a></li><li><span class="hits">05-06</span><span class="num">4.</span><a href="/book/5094/" title="雪鹰领主" target="_blank">雪鹰领主</a></li><li><span class="hits">05-01</span><span class="num">15.</span><a href="/book/365/" title="武动乾坤" target="_blank">武动乾坤</a></li></ul></div>

发现所有的小说都是在一个个列表里,并且里面清晰的定义了:

标题:title = div.a['title']
链接:link = 'http://www.qu.la/' + div.a['href']

这样一来,我们只需要在当前页面找到所有小说的连接,并保存在列表就行了。

列表去重的小技巧:

信息的同学会发现,就算是不同类别的小说,也是会重复出现在排行榜的。
这样无形之间就会浪费我们很多资源,尤其是在面对爬大量网页的时候。
那么我们如何从抓取的url列表里去重呢? 
刚学Python的小伙伴可能会去实现一个循环算法,来去重,
但是Python的强大之处就在于他可以通过及其优美的方式来解决很多问题,这里其实只要一行代码就能解决:

url_list = list(set(url_list))

这里我们调用了一个list的构造函数set:这样就能保证列表里没有重复的元素了。是不是很简单?

单个小说所有章节链接:

首先我们从前面获取到的小说url连接选取一个做实验:
比如我最爱的择天记:

http://www.qu.la/book/168/

依然是无比清晰的网页结构,点个赞:

<div class="box_con">
<div id="list">
<dl><dt>《择天记》正文</dt><dd> <a style="" href="/book/168/1748915.html">序 下山</a></dd><dd> <a style="" href="/book/168/1748916.html">第一章 我改主意了</a></dd><dd> <a style="" href="/book/168/1748917.html">第二章 为什么</a></dd><!-- 中间章节省略了 --><dd> <a style="" href="/book/168/1748924.html">第九章 我有做错什么吗?</a></dd></div>

我们可以很容易的找到对应章节的连接:
这个代码是节选,不能直接用!后面会有说明

link='http://www.qu.la/' + url.a['href']

好的,这样我们就能把一篇小说的所有章节的链接爬下来了。
剩下最后一步:爬取文章内容:

文章内容的爬取:

首先我们打开一章,并查看他的源代码:

我们能发现所有的正文内容,都保存在:

<div id='content'>

所有的章节名就更简单了:

<h1> 第一章 我改主意了</h1>

那我们通过bs4库的各种标签的查找方法,就能很简单的找到啦
好了,让我们看看具体代码的实现:

代码的实现:

模块化,函数式编程是一个非常好的习惯,我们坚持把每一个独立的功能都写成函数,这样会使你的代码简单又可复用。

网页抓取头:

def get_html(url):try:r = requests.get(url, timeout=30)r.raise_for_status# 我手动测试了编码。并设置好,这样有助于效率的提升r.encoding = ('utr-8')return r.textexcept:return "Someting Wrong!"

获取排行榜小说及其链接:

def get_content(url):'''
    爬取每一类型小说排行榜,
    按顺序写入文件,
    文件内容为 小说名字+小说链接
    将内容保存到列表
    并且返回一个装满url链接的列表
    '''url_list = []html = get_html(url)soup = bs4.BeautifulSoup(html, 'lxml')# 由于小说排版的原因,历史类和完本类小说不在一个div里category_list = soup.find_all('div', class_='index_toplist mright mbottom')history_finished_list = soup.find_all('div', class_='index_toplist mbottom')for cate in category_list:name = cate.find('div', class_='toptab').span.stringwith open('novel_list.csv', 'a+') as f:f.write("\n小说种类:{} \n".format(name))# 我们直接通过style属性来定位总排行榜general_list = cate.find(style='display: block;')# 找到全部的小说名字,发现他们全部都包含在li标签之中book_list = general_list.find_all('li')# 循环遍历出每一个小说的的名字,以及链接for book in book_list:link = 'http://www.qu.la/' + book.a['href']title = book.a['title']# 我们将所有文章的url地址保存在一个列表变量里url_list.append(link)# 这里使用a模式,防止清空文件with open('novel_list.csv', 'a') as f:f.write("小说名:{:<} \t 小说地址:{:<} \n".format(title, link))for cate in history_finished_list:name = cate.find('div', class_='toptab').span.stringwith open('novel_list.csv', 'a') as f:f.write("\n小说种类:{} \n".format(name))general_list = cate.find(style='display: block;')book_list = general_list.find_all('li')for book in book_list:link = 'http://www.qu.la/' + book.a['href']title = book.a['title']url_list.append(link)with open('novel_list.csv', 'a') as f:f.write("小说名:{:<} \t 小说地址:{:<} \n".format(title, link))return url_list

获取单本小说的所有章节链接:

def get_txt_url(url):'''
    获取该小说每个章节的url地址:
    并创建小说文件    '''url_list = []html = get_html(url)soup = bs4.BeautifulSoup(html, 'lxml')lista = soup.find_all('dd')txt_name = soup.find('h1').textwith open('/Users/ehco/Documents/codestuff/Python-crawler/小说/{}.txt'.format(txt_name), "a+") as f:f.write('小说标题:{} \n'.format(txt_name))for url in lista:url_list.append('http://www.qu.la/' + url.a['href'])return url_list, txt_name

获取单页文章的内容并保存到本地:

这里有个小技巧:
我们从网上趴下来的文件很多时候都是带着<br>之类的格式化标签,
我们可以通过一个简单的方法把他过滤掉:
html = get_html(url).replace('<br/>', '\n')
我这里单单过滤了一种标签,并将其替换成‘\n’用于文章的换行,
具体怎么扩展,大家可以开动一下自己的脑袋啦

还有,我这里的代码是不能直接在你们的机子上用的,
因为在写入文件的时候,绝对目录不一样

def get_one_txt(url, txt_name):'''
    获取小说每个章节的文本
    并写入到本地
    '''html = get_html(url).replace('<br/>', '\n')soup = bs4.BeautifulSoup(html, 'lxml')try:txt = soup.find('div', id='content').text.replace('chaptererror();', '')title = soup.find('title').textwith open('/Users/ehco/Documents/codestuff/Python-crawler/小说/{}.txt'.format(txt_name), "a") as f:f.write(title + '\n\n')f.write(txt)print('当前小说:{} 当前章节{} 已经下载完毕'.format(txt_name, title))except:print('someting wrong')

缺点:

本次爬虫写的这么顺利,更多的是因为爬的网站是没有反爬虫技术,以及文章分类清晰,结构优美。
但是,按照我们的这篇文的思路去爬取小说,

我大概计算了一下:
一篇文章需要:0.5s
一本小说(1000张左右):8.5分钟
全部排行榜(60本): 8.5小时!

是的! 时间太长了!
那么,这种单线程的爬虫,速度如何能提高呢?
自己洗个多线程模块?

其实还有更好的方式:下一个大的章节我们将一起学习Scrapy框架
学到那里的时候,我再把这里代码重构一边,
你会惊奇的发现,速度几十倍甚至几百倍的提高了!
这其实也是多线程的威力!

最后看一下结果吧:

排行榜结果:

小说结果:

学到这里是不是越来越喜欢爬虫这个神奇的东西了呢?
加油,更神奇的东西还在后面呢!

每天的学习记录都会 同步更新到:
微信公众号: findyourownway

知乎专栏:从零开始写Python爬虫 - 知乎专栏

blog : www.ehcoblog.ml

Github: Ehco1996/Python-crawler

从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载相关推荐

  1. python 小说爬虫_从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载

    从零开始写Python爬虫 --- 1.7 爬虫实践: 排行榜小说批量下载Ehco 5 个月前 本来只是准备做一个爬起点小说名字的爬虫,后来想了一下,为啥不顺便把小说的内容也爬下来呢?于是我就写了这个 ...

  2. 从零开始写Python爬虫 --- 1.5 爬虫实践: 获取百度贴吧内容

    从零开始写Python爬虫 --- 1.5 爬虫实践: 获取百度贴吧内容 Ehco 5 个月前 经过前期大量的学习与准备,我们重要要开始写第一个真正意义上的爬虫了.本次我们要爬取的网站是:百度贴吧,一 ...

  3. python爬虫代理的使用_从零开始写Python爬虫 --- 2.4 爬虫实践:代理的爬取和验证...

    爬网站的时候,由于各种原因,ip被锁了,这个时候我们就需要通过代理来突破封锁.网上有很多代理网站,付费和免费的都有,这次我们就来写一个scrapy爬虫,爬一些免费的代理下来用. 目标分析: 本次爬取了 ...

  4. python 模拟浏览器selenium_从零开始写Python爬虫 --- 3.1 Selenium模拟浏览器

    本来说好要写Mechanize模拟浏览器的,结果一看居然只支持2.x版本的Python,而且已经长久没有更新维护了,本着学新不学旧的原则,我决定跳过他,直接开学Selenium(其实就是我懒,逃 Se ...

  5. 孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9并使用pydocx模块将结果写入word文档...

    孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 到今天终于完成了对docx模块针对 ...

  6. 从零开始写Python爬虫 --- 1.5 爬虫实践: 笔趣阁小说批量下载

    目标网站 首先来看看我们排行榜的地址: http://www.qu.la/paihangbang/ 我们的目的很明确:找到各类排行旁的的每一部小说的名字和在该网站的链接. 网站分析 首先观察一下网页的 ...

  7. 从零开始写Python爬虫---1.1 requests库的安装与使用

    什么是爬虫? 爬虫本质上是模拟人浏览信息的过程,只不过他通过计算机来达到快速抓取筛选信息的目的.所以我们想要写一个爬虫,最基本的就是要将我们需要抓取信息的网页原原本本的抓取下来.这个时候就要用到req ...

  8. python爬取知乎评论_从零开始写Python爬虫 --- 爬虫应用:IT之家热门段子(评论)爬取...

    不知道这里有没有喜欢刷it之家的小伙伴,我反正每天早上醒来第一件事就是打开it之家,看看有没有新鲜的段子 逃~ 其实这次是要来抓取it之家的热门评论,因为数量较多(上万),所以我们这次采用MongoD ...

  9. Python爬虫实战,Request+urllib模块,批量下载爬取飙歌榜所有音乐文件

    前言 今天给大家介绍的是Python爬取飙歌榜所有音频数据并保存本地,在这里给需要的小伙伴们代码,并且给出一点小心得. 首先是爬取之前应该尽可能伪装成浏览器而不被识别出来是爬虫,基本的是加请求头,但是 ...

最新文章

  1. 在linux中只将“桌面”修改成“Desktop”而系统仍然使用中文
  2. Fiddler学习之——对Android应用进行抓包
  3. linux下搭建git服务器
  4. php中有两个美元符号$$的变量——可变变量
  5. java8 foreach 异常_错误处理 – 在java 8流foreach中抛出异常
  6. H264 编码+打包+解码相关知识
  7. 模式识别算法:SVM支持向量机
  8. photoshop标尺工具_工具设置:PhotoShop
  9. Canvas 仿百度贴吧客户端 loading 小球
  10. Linux服务篇之DNS域名解析服务
  11. iOS10.3正式版发布:iOS10.3新功能有哪些? 韩俊强的博客
  12. 安装计算机的显卡出现问题,电脑显卡驱动安装失败如何解决
  13. 【Android 2D 游戏开发(5)】——九宫格拼图(苍老师版)
  14. LineMod源码梳理
  15. 开发自己的编程语言(五)—— CIL中间代码的生成
  16. 彻底终结敲诈者 360独家推出“文档卫士”
  17. 【深度学习】超详细的 PyTorch 学习笔记(上)
  18. Windows域结构关系及基本信息
  19. 常见三维文件格式之IGES
  20. Linux 字符串截取方法

热门文章

  1. 什么是酷雷曼VR全景视图?全景图拼接的原理是什么?
  2. 【CSS】少年,你想拥有写轮眼么?
  3. 中国商业地产投资专业展览会6月在京举办
  4. 字符串转LocalDateTime
  5. 真实的上海IT圈:张江男vs漕河泾男(文末送书)
  6. 微信公众号测试账号申请,后台获取公众号关注取关事件,获取用户发送消息
  7. ByteBuffer介绍
  8. 【转载】使用tcp.validnode_checking允许、限制机器访问数据库
  9. Java SE_封装、继承、object类、super-this关键字、方法重写、多态、instanceof、类型转换
  10. linux 网络命令 mii-tool 和 ethtool 使用