编写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="">(.*?)</h1>',unicodePage,re.S) my_title = my_title.group(1) except: print '标题 HTML 变化,请重新分析!' return False try: #抓取章节内容 my_content = re.search('<div.*?id="htmlContent" class="contentbox">(.*?)<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="">(.*?)</h1>',unicodePage,re.S) my_title = my_title.group(1) except: print '标题 HTML 变化,请重新分析!' return False try: #抓取章节内容 my_content = re.search('<div.*?id="htmlContent" class="contentbox">(.*?)<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.*?class="chapter_Turnpage">(.*?)</div>',unicodePage,re.S) foot_link = foot_link.group(1) #在连接的区域找下一页的连接,根据网页特点为第三个 nextUrl = re.findall(u'<a.*?href="(.*?)".*?>(.*?)</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="">(.*?)</h1>',unicodePage,re.S) my_title = my_title.group(1) except: print '标题 HTML 变化,请重新分析!' return False try: #抓取章节内容 my_content = re.search('<div.*?id="htmlContent" class="contentbox">(.*?)<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.*?class="chapter_Turnpage">(.*?)</div>',unicodePage,re.S) foot_link = foot_link.group(1) #在连接的区域找下一页的连接,根据网页特点为第三个 nextUrl = re.findall(u'<a.*?href="(.*?)".*?>(.*?)</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()

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











PHP와 Python은 고유 한 장점과 단점이 있으며 선택은 프로젝트 요구와 개인 선호도에 달려 있습니다. 1.PHP는 대규모 웹 애플리케이션의 빠른 개발 및 유지 보수에 적합합니다. 2. Python은 데이터 과학 및 기계 학습 분야를 지배합니다.

CentOS 시스템에서 Pytorch 모델을 효율적으로 교육하려면 단계가 필요 하며이 기사는 자세한 가이드를 제공합니다. 1. 환경 준비 : 파이썬 및 종속성 설치 : CentOS 시스템은 일반적으로 파이썬을 사전 설치하지만 버전은 더 오래 될 수 있습니다. YUM 또는 DNF를 사용하여 Python 3 및 Upgrade Pip : Sudoyumupdatepython3 (또는 SudodnfupdatePython3), PIP3INSTALL-UPGRADEPIP를 설치하는 것이 좋습니다. CUDA 및 CUDNN (GPU 가속도) : NVIDIAGPU를 사용하는 경우 Cudatool을 설치해야합니다.

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

CentOS 시스템에서 Pytorch GPU 가속도를 활성화하려면 Cuda, Cudnn 및 GPU 버전의 Pytorch를 설치해야합니다. 다음 단계는 프로세스를 안내합니다. CUDA 및 CUDNN 설치 CUDA 버전 호환성 결정 : NVIDIA-SMI 명령을 사용하여 NVIDIA 그래픽 카드에서 지원하는 CUDA 버전을보십시오. 예를 들어, MX450 그래픽 카드는 CUDA11.1 이상을 지원할 수 있습니다. Cudatoolkit 다운로드 및 설치 : NVIDIACUDATOOLKIT의 공식 웹 사이트를 방문하여 그래픽 카드에서 지원하는 가장 높은 CUDA 버전에 따라 해당 버전을 다운로드하여 설치하십시오. CUDNN 라이브러리 설치 :

Docker는 Linux 커널 기능을 사용하여 효율적이고 고립 된 응용 프로그램 실행 환경을 제공합니다. 작동 원리는 다음과 같습니다. 1. 거울은 읽기 전용 템플릿으로 사용되며, 여기에는 응용 프로그램을 실행하는 데 필요한 모든 것을 포함합니다. 2. Union 파일 시스템 (Unionfs)은 여러 파일 시스템을 스택하고 차이점 만 저장하고 공간을 절약하고 속도를 높입니다. 3. 데몬은 거울과 컨테이너를 관리하고 클라이언트는 상호 작용을 위해 사용합니다. 4. 네임 스페이스 및 CGroup은 컨테이너 격리 및 자원 제한을 구현합니다. 5. 다중 네트워크 모드는 컨테이너 상호 연결을 지원합니다. 이러한 핵심 개념을 이해 함으로써만 Docker를 더 잘 활용할 수 있습니다.

Centos에서 Pytorch 버전을 선택할 때 다음과 같은 주요 요소를 고려해야합니다. 1. Cuda 버전 호환성 GPU 지원 : NVIDIA GPU가 있고 GPU 가속도를 사용하려면 해당 CUDA 버전을 지원하는 Pytorch를 선택해야합니다. NVIDIA-SMI 명령을 실행하여 지원되는 CUDA 버전을 볼 수 있습니다. CPU 버전 : GPU가 없거나 GPU를 사용하지 않으려면 Pytorch의 CPU 버전을 선택할 수 있습니다. 2. 파이썬 버전 Pytorch

Centos Nginx를 설치하려면 다음 단계를 수행해야합니다. 개발 도구, PCRE-DEVEL 및 OPENSSL-DEVEL과 같은 종속성 설치. nginx 소스 코드 패키지를 다운로드하고 압축을 풀고 컴파일하고 설치하고 설치 경로를/usr/local/nginx로 지정하십시오. nginx 사용자 및 사용자 그룹을 만들고 권한을 설정하십시오. 구성 파일 nginx.conf를 수정하고 청취 포트 및 도메인 이름/IP 주소를 구성하십시오. Nginx 서비스를 시작하십시오. 종속성 문제, 포트 충돌 및 구성 파일 오류와 같은 일반적인 오류는주의를 기울여야합니다. 캐시를 켜고 작업자 프로세스 수 조정과 같은 특정 상황에 따라 성능 최적화를 조정해야합니다.

CentOS 시스템에 대한 Pytorch 분산 교육에는 다음 단계가 필요합니다. Pytorch 설치 : 전제는 Python과 PIP가 CentOS 시스템에 설치된다는 것입니다. CUDA 버전에 따라 Pytorch 공식 웹 사이트에서 적절한 설치 명령을 받으십시오. CPU 전용 교육의 경우 다음 명령을 사용할 수 있습니다. PipinStalltorchtorchvisiontorchaudio GPU 지원이 필요한 경우 CUDA 및 CUDNN의 해당 버전이 설치되어 있는지 확인하고 해당 PyTorch 버전을 설치하려면 설치하십시오. 분산 환경 구성 : 분산 교육에는 일반적으로 여러 기계 또는 단일 기계 다중 GPU가 필요합니다. 장소
