目录
(.*?)
首页 后端开发 Python教程 编写Python脚本抓取网络小说来制作自己的阅读器

编写Python脚本抓取网络小说来制作自己的阅读器

Jun 10, 2016 pm 03:07 PM
python 抓取

你是否苦恼于网上无法下载的“小说在线阅读”内容?或是某些文章的内容让你很有收藏的冲动,却找不到一个下载的链接?是不是有种自己写个程序把全部搞定的冲动?是不是学了 python,想要找点东西大展拳脚,告诉别人“哥可是很牛逼的!”?那就让我们开始吧! 哈哈~
    好吧,我就是最近写 Yii 写多了,想找点东西调剂一下.... = =

    本项目以研究为目的,所有版权问题我们都是站在作者的一边,以看盗版小说为目的的读者们请自行面壁!
    说了这么多,我们要做的就是把小说正文的内容从网页上爬下来,我们的研究对象是全本小说网....再次声明,不对任何版权负责....
    一开始先做最基础的内容,就是把某一章的内容抓取下来。

    环境:Ubuntu, Python 2.7

    基础知识
    这个程序涉及到的知识点有几个,在这里列出来,不详细讲,有疑问的直接百度会有一堆的。
    1.urllib2 模块的 request 对像来设置 HTTP 请求,包括抓取的 url,和伪装浏览器的代理。然后就是 urlopen 和 read 方法,都很好理解。
    2.chardet 模块,用于检测网页的编码。在网页上抓取数据很容易遇到乱码的问题,为了判断网页是 gtk 编码还是 utf-8 ,所以用 chardet 的 detect 函数进行检测。在用 Windows 的同学可以在这里 http://download.csdn.net/detail/jcjc918/8231371 下载,解压到 python 的 lib 目录下就好。
    3. decode 函数将字符串从某种编码转为 unicode 字符,而 encode 把 unicode 字符转为指定编码格式的字符串。
     4. re 模块正则表达式的应用。search 函数可以找到和正则表达式对应匹配的一项,而 replace 则是把匹配到的字符串替换。

    思路分析:
    我们选取的 url 是 http://www.quanben.com/xiaoshuo/0/910/59302.html,斗罗大陆的第一章。你可以查看网页的源代码,会发现只有一个 content 标签包含了所有章节的内容,所以可以用正则把 content 的标签匹配到,抓取下来。试着把这一部分内容打印出来,会发现很多
和  ,
要替换成换行符,   是网页中的占位符,即空格,替换成空格就好。这样一章的内容就很美观的出来了。完整起见,同样用正则把标题爬下来。

    程序

# -*- coding: utf-8 -*- 
 
import urllib2 
import re 
import chardet 
 
 
class Book_Spider: 
 
  def __init__(self): 
    self.pages = [] 
 
  # 抓取一个章节 
  def GetPage(self): 
    myUrl = "http://www.quanben.com/xiaoshuo/0/910/59302.html"; 
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' 
    headers = { 'User-Agent' : user_agent } 
    request = urllib2.Request(myUrl, headers = headers) 
    myResponse = urllib2.urlopen(request) 
    myPage = myResponse.read() 
 
    #先检测网页的字符编码,最后统一转为 utf-8 
    charset = chardet.detect(myPage) 
    charset = charset['encoding'] 
    if charset == 'utf-8' or charset == 'UTF-8': 
      myPage = myPage 
    else: 
      myPage = myPage.decode('gb2312','ignore').encode('utf-8') 
    unicodePage = myPage.decode("utf-8") 
 
    try: 
      #抓取标题 
      my_title = re.search('<h1 id="">(.*&#63;)</h1>',unicodePage,re.S) 
      my_title = my_title.group(1) 
    except: 
      print '标题 HTML 变化,请重新分析!' 
      return False 
     
    try: 
      #抓取章节内容 
      my_content = re.search('<div.*&#63;id="htmlContent" class="contentbox">(.*&#63;)<div',unicodePage,re.S) 
      my_content = my_content.group(1) 
    except: 
      print "内容 HTML 变化,请重新分析!" 
      return False 
     
    #替换正文中的网页代码 
    my_content = my_content.replace("<br />","\n") 
    my_content = my_content.replace(" "," ") 
 
    #用字典存储一章的标题和内容 
    onePage = {'title':my_title,'content':my_content} 
    return onePage 
 
 
  # 用于加载章节 
  def LoadPage(self): 
    try: 
      # 获取新的章节 
      myPage = self.GetPage() 
       
      if myPage == False: 
        print '抓取失败!' 
        return False 
       
      self.pages.append(myPage) 
    except: 
      print '无法连接服务器!' 
 
  #显示一章 
  def ShowPage(self,curPage): 
      print curPage['title'] 
      print curPage['content'] 
 
  def Start(self): 
    print u'开始阅读......\n' 
    #把这一页加载进来 
    self.LoadPage() 
    # 如果self的pages数组中存有元素 
    if self.pages: 
      nowPage = self.pages[0] 
      self.ShowPage(nowPage) 
 
 
#----------- 程序的入口处 ----------- 
print u""" 
--------------------------------------- 
  程序:阅读呼叫转移 
  版本:0.1 
  作者:angryrookie 
  日期:2014-07-05 
  语言:Python 2.7 
  功能:按下回车浏览章节 
--------------------------------------- 
""" 
 
print u'请按下回车:' 
raw_input() 
myBook = Book_Spider() 
myBook.Start() 
登录后复制

程序运行完在我这里可是很好看的,不信请看:^_^

理所当然地,接下来我们要把整本小说都爬下来。首先,我们要把程序从原来的读完一章就结束,改成读完一章之后可以继续进行下一章的阅读。
注意到每个小说章节的网页下面都有下一页的链接。通过查看网页源代码,稍微整理一下( 不显示了),我们可以看到这一部分的 HTML 是下面这种格式的:

<div id="footlink"> 
 <script type="text/javascript" charset="utf-8" src="/scripts/style5.js"></script> 
 <a href="http://www.quanben.com/xiaoshuo/0/910/59301.html">上一页</a>   
 <a href="http://www.quanben.com/xiaoshuo/0/910/">返回目录</a>   
 <a href="http://www.quanben.com/xiaoshuo/0/910/59303.html">下一页</a> 
</div> 
登录后复制

上一页 、返回目录、下一页都在一个 id 为 footlink 的 div 中,如果想要对每个链接进行匹配的话,会抓取到网页上大量的其他链接,但是 footlink 的 div 只有一个啊!我们可以把这个 div 匹配到,抓下来,然后在这个抓下来的 div 里面再匹配 的链接,这时就只有三个了。只要取最后一个链接就是下一页的 url 的,用这个 url 更新我们抓取的目标 url ,这样就能一直抓到下一页。用户阅读逻辑为每读一个章节后,等待用户输入,如果是 quit 则退出程序,否则显示下一章。

基础知识:
上一篇的基础知识加上 Python 的 thread 模块.

源代码:

# -*- coding: utf-8 -*- 
 
import urllib2 
import re 
import thread 
import chardet 
 
class Book_Spider: 
 
  def __init__(self): 
    self.pages = [] 
    self.page = 1 
    self.flag = True 
    self.url = "http://www.quanben.com/xiaoshuo/10/10412/2095096.html" 
 
  # 将抓取一个章节 
  def GetPage(self): 
    myUrl = self.url 
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' 
    headers = { 'User-Agent' : user_agent } 
    req = urllib2.Request(myUrl, headers = headers) 
    myResponse = urllib2.urlopen(req) 
    myPage = myResponse.read() 
 
    charset = chardet.detect(myPage) 
    charset = charset['encoding'] 
    if charset == 'utf-8' or charset == 'UTF-8': 
      myPage = myPage 
    else: 
      myPage = myPage.decode('gb2312','ignore').encode('utf-8') 
    unicodePage = myPage.decode("utf-8") 
 
    # 找出 id="content"的div标记 
    try: 
      #抓取标题 
      my_title = re.search('<h1 id="">(.*&#63;)</h1>',unicodePage,re.S) 
      my_title = my_title.group(1) 
    except: 
      print '标题 HTML 变化,请重新分析!' 
      return False 
     
    try: 
      #抓取章节内容 
      my_content = re.search('<div.*&#63;id="htmlContent" class="contentbox">(.*&#63;)<div',unicodePage,re.S) 
      my_content = my_content.group(1) 
    except: 
      print "内容 HTML 变化,请重新分析!" 
      return False 
     
    my_content = my_content.replace("<br />","\n") 
    my_content = my_content.replace(" "," ") 
 
    #用字典存储一章的标题和内容 
    onePage = {'title':my_title,'content':my_content} 
 
    try: 
      #找到页面下方的连接区域 
      foot_link = re.search('<div.*&#63;class="chapter_Turnpage">(.*&#63;)</div>',unicodePage,re.S) 
      foot_link = foot_link.group(1) 
      #在连接的区域找下一页的连接,根据网页特点为第三个 
      nextUrl = re.findall(u'<a.*&#63;href="(.*&#63;)".*&#63;>(.*&#63;)</a>',foot_link,re.S) 
      nextUrl = nextUrl[2][0] 
      # 更新下一次进行抓取的链接 
      self.url = nextUrl 
    except: 
      print "底部链接变化,请重新分析!" 
      return False 
 
    return onePage 
 
  # 用于加载章节 
  def LoadPage(self): 
    while self.flag: 
      if(len(self.pages) - self.page < 3): 
        try: 
          # 获取新的页面 
          myPage = self.GetPage() 
 
          if myPage == False: 
            print '抓取失败!' 
            self.flag = False 
       
          self.pages.append(myPage) 
        except: 
          print '无法连接网页!' 
          self.flag = False 
 
  #显示一章 
  def ShowPage(self,curPage): 
      print curPage['title'] 
      print curPage['content'] 
      print "\n" 
      user_input = raw_input("当前是第 %d 章,回车读取下一章或者输入 quit 退出:" % self.page) 
      if(user_input == 'quit'): 
        self.flag = False 
      print "\n" 
 
  def Start(self): 
    print u'开始阅读......\n' 
 
    # 新建一个线程 
    thread.start_new_thread(self.LoadPage,()) 
 
    # 如果self的page数组中存有元素 
    while self.flag: 
      if self.page <= len(self.pages): 
        nowPage = self.pages[self.page-1] 
        self.ShowPage(nowPage) 
        self.page += 1 
 
    print u"本次阅读结束" 
 
 
#----------- 程序的入口处 ----------- 
print u""" 
--------------------------------------- 
  程序:阅读呼叫转移 
  版本:0.2 
  作者:angryrookie 
  日期:2014-07-07 
  语言:Python 2.7 
  功能:按下回车浏览下一章节 
--------------------------------------- 
""" 
 
print u'请按下回车:' 
raw_input(' ') 
myBook = Book_Spider() 
myBook.Start() 

登录后复制

现在这么多小说阅读器,我们只需要把我们要的小说抓取到本地的 txt 文件里就好了,然后自己选个阅读器看,怎么整都看你了。

其实上个程序我们已经完成了大部分逻辑,我们接下来的改动只需要把抓取到每一章的时候不用显示出来,而是存入 txt 文件之中。另外一个是程序是不断地根据下一页的 Url 进行抓取的,那么什么时候结束呢?注意当到达小说的最后一章时下一页的链接是和返回目录的链接是一样的。所以我们抓取一个网页的时候就把这两个链接拿出来,只要出现两个链接一样的时候,就停止抓取。最后就是我们这个程序不需要多线程了,我们只要一个不断在抓取小说页面的线程就行了。
不过,小说章节多一点时候,等待完成的时间会有点久。目前就不考虑这么多了,基本功能完成就 OK....

基础知识:前面的基础知识 - 多线程知识 + 文件操作知识。

源代码:

# -*- coding:utf-8 -*- 
 
import urllib2 
import urllib 
import re 
import thread 
import chardet 
 
class Book_Spider: 
 
  def __init__(self): 
    self.pages = [] 
    self.page = 1 
    self.flag = True 
    self.url = "http://www.quanben.com/xiaoshuo/0/910/59302.html" 
 
  # 将抓取一个章节 
  def GetPage(self): 
    myUrl = self.url 
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' 
    headers = { 'User-Agent' : user_agent } 
    req = urllib2.Request(myUrl, headers = headers) 
    myResponse = urllib2.urlopen(req) 
    myPage = myResponse.read() 
 
    charset = chardet.detect(myPage) 
    charset = charset['encoding'] 
    if charset == 'utf-8' or charset == 'UTF-8': 
      myPage = myPage 
    else: 
      myPage = myPage.decode('gb2312','ignore').encode('utf-8') 
    unicodePage = myPage.decode("utf-8") 
 
    # 找出 id="content"的div标记 
    try: 
      #抓取标题 
      my_title = re.search('<h1 id="">(.*&#63;)</h1>',unicodePage,re.S) 
      my_title = my_title.group(1) 
    except: 
      print '标题 HTML 变化,请重新分析!' 
      return False 
     
    try: 
      #抓取章节内容 
      my_content = re.search('<div.*&#63;id="htmlContent" class="contentbox">(.*&#63;)<div',unicodePage,re.S) 
      my_content = my_content.group(1) 
    except: 
      print "内容 HTML 变化,请重新分析!" 
      return False 
     
    my_content = my_content.replace("<br />","\n") 
    my_content = my_content.replace(" "," ") 
 
    #用字典存储一章的标题和内容 
    onePage = {'title':my_title,'content':my_content} 
 
    try: 
      #找到页面下方的连接区域 
      foot_link = re.search('<div.*&#63;class="chapter_Turnpage">(.*&#63;)</div>',unicodePage,re.S) 
      foot_link = foot_link.group(1) 
      #在连接的区域找下一页的连接,根据网页特点为第三个 
      nextUrl = re.findall(u'<a.*&#63;href="(.*&#63;)".*&#63;>(.*&#63;)</a>',foot_link,re.S) 
      #目录链接 
      dir_url = nextUrl[1][0] 
      nextUrl = nextUrl[2][0] 
      # 更新下一次进行抓取的链接 
      self.url = nextUrl 
 
      if(dir_url == nextUrl): 
        self.flag = False 
         
      return onePage 
    except: 
      print "底部链接变化,请重新分析!" 
      return False 
 
  # 用于加载章节 
  def downloadPage(self): 
 
    f_txt = open(u"斗罗大陆.txt",'w+') 
    while self.flag: 
      try: 
        # 获取新的页面 
        myPage = self.GetPage() 
         
        if myPage == False: 
            print '抓取失败!' 
            self.flag = False 
 
        title = myPage['title'].encode('utf-8') 
        content = myPage['content'].encode('utf-8') 
 
        f_txt.write(title + '\n\n') 
        f_txt.write(content) 
        f_txt.write('\n\n\n') 
 
        print "已下载 ",myPage['title'] 
 
      except: 
        print '无法连接服务器!' 
        self.flag = False 
         
    f_txt.close() 
 
  def Start(self): 
    print u'开始下载......\n' 
 
    self.downloadPage() 
 
 
    print u"下载完成" 
 
 
#----------- 程序的入口处 ----------- 
print u""" 
--------------------------------------- 
  程序:阅读呼叫转移 
  版本:0.3 
  作者:angryrookie 
  日期:2014-07-08 
  语言:Python 2.7 
  功能:按下回车开始下载 
--------------------------------------- 
""" 
 
print u'请按下回车:' 
raw_input(' ') 
myBook = Book_Spider() 
myBook.Start() 
登录后复制

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP和Python:代码示例和比较 PHP和Python:代码示例和比较 Apr 15, 2025 am 12:07 AM

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。

Python vs. JavaScript:社区,图书馆和资源 Python vs. JavaScript:社区,图书馆和资源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

docker原理详解 docker原理详解 Apr 14, 2025 pm 11:57 PM

Docker利用Linux内核特性,提供高效、隔离的应用运行环境。其工作原理如下:1. 镜像作为只读模板,包含运行应用所需的一切;2. 联合文件系统(UnionFS)层叠多个文件系统,只存储差异部分,节省空间并加快速度;3. 守护进程管理镜像和容器,客户端用于交互;4. Namespaces和cgroups实现容器隔离和资源限制;5. 多种网络模式支持容器互联。理解这些核心概念,才能更好地利用Docker。

visual studio code 可以用于 python 吗 visual studio code 可以用于 python 吗 Apr 15, 2025 pm 08:18 PM

VS Code 可用于编写 Python,并提供许多功能,使其成为开发 Python 应用程序的理想工具。它允许用户:安装 Python 扩展,以获得代码补全、语法高亮和调试等功能。使用调试器逐步跟踪代码,查找和修复错误。集成 Git,进行版本控制。使用代码格式化工具,保持代码一致性。使用 Linting 工具,提前发现潜在问题。

vscode怎么在终端运行程序 vscode怎么在终端运行程序 Apr 15, 2025 pm 06:42 PM

在 VS Code 中,可以通过以下步骤在终端运行程序:准备代码和打开集成终端确保代码目录与终端工作目录一致根据编程语言选择运行命令(如 Python 的 python your_file_name.py)检查是否成功运行并解决错误利用调试器提升调试效率

vs code 可以在 Windows 8 中运行吗 vs code 可以在 Windows 8 中运行吗 Apr 15, 2025 pm 07:24 PM

VS Code可以在Windows 8上运行,但体验可能不佳。首先确保系统已更新到最新补丁,然后下载与系统架构匹配的VS Code安装包,按照提示安装。安装后,注意某些扩展程序可能与Windows 8不兼容,需要寻找替代扩展或在虚拟机中使用更新的Windows系统。安装必要的扩展,检查是否正常工作。尽管VS Code在Windows 8上可行,但建议升级到更新的Windows系统以获得更好的开发体验和安全保障。

vscode 扩展是否是恶意的 vscode 扩展是否是恶意的 Apr 15, 2025 pm 07:57 PM

VS Code 扩展存在恶意风险,例如隐藏恶意代码、利用漏洞、伪装成合法扩展。识别恶意扩展的方法包括:检查发布者、阅读评论、检查代码、谨慎安装。安全措施还包括:安全意识、良好习惯、定期更新和杀毒软件。

Python:自动化,脚本和任务管理 Python:自动化,脚本和任务管理 Apr 16, 2025 am 12:14 AM

Python在自动化、脚本编写和任务管理中表现出色。1)自动化:通过标准库如os、shutil实现文件备份。2)脚本编写:使用psutil库监控系统资源。3)任务管理:利用schedule库调度任务。Python的易用性和丰富库支持使其在这些领域中成为首选工具。

See all articles