Python3利用BeautifulSoup4抓取站点小说全文的代码

再写一个用BeautifulSoup抓站的工具,体会BeautifulSoup的强大。

根据小说索引页获取小说全部章节内容并在本地整合为小说全文。不过不是智能的,不同的站点对代码需要做相应的修改。

#!/usr/bin/env python

import os
import sys
import re
import time
import chardet
import urllib.request as ur
from urllib.parse import urljoin,urlparse
from bs4 import BeautifulSoup
from threading import Thread

class Download(Thread):                          #为每个章节分配多线程
    def __init__(self,filepath,info):
        Thread.__init__(self)
        self.filepath = filepath
        (self.link,self.chapter) = info

    def run(self):
        print(‘开始下载: ‘+self.chapter)
        section(self.filepath,self.chapter,self.link)
        print(‘完成下载: ‘+self.chapter)

def getData(url):                          #主要用于判断页面编码,但是发现BeautifulSoup自带判定能力,故废弃此函数
    charsets = ‘utf8‘
    response = ur.urlopen(url,timeout = 10)
    html = response.read()
    charinfo = chardet.detect(html)
    charsets = charinfo[‘encoding‘]
    data = html.decode(charsets)
    return data

def merge(tmpFiles,targetFile):             #将下载的章节合并
    for tmpFile in tmpFiles:
        with open(targetFile,‘a+‘) as wfile:
            wfile.write(open(tmpFile,‘r‘).read())
        os.remove(tmpFile)

def content(link):                         #获取章节页面的小说内容。对于不同的站点,在此函数内修改获取章节内容的代码
    html = ur.urlopen(link,timeout = 10)
    soup =BeautifulSoup(html)
    contents = soup.find(id = ‘readtext‘).p.span.text.replace(‘  ‘,‘\n‘)   #BeautifulSoup会自动将&nbsp;转换为空格,<br/>转换为特殊符号
    return contents

def section(filepath,chapter,link):         #下载章节内容
    while True:                #反复请求页面
        try:
            with open(filepath,‘w‘) as nfile:
                nfile.write(chapter+‘\n‘+content(link)+‘\n‘)
            break
        except:
            pass

def index(url):
    indexs = []
    while True:                   #反复请求页面
        try:
            html = ur.urlopen(url,timeout = 10)
            #html = html.read().decode(‘gb2312‘)
            #html = getData(url)
            soup = BeautifulSoup(html,from_encoding = ‘gbk‘)#BeautifulSoup能自动识别编码,但是会将gbk页面识别为gb2312页面,可能导致页面内部分数据获取失败
            break
        except:
            pass
    title = soup.find(name = ‘div‘,attrs = {‘class‘:‘booktext‘}).text
    indexDiv = soup.find(name = ‘div‘,attrs = {‘class‘:‘booktext‘})
    indexUl = [ul for ul in indexDiv.find_all(‘ul‘) if ul][1:]
    for ul in indexUl:
        indexList = [li.a for li in ul.find_all(‘li‘) if li]
        index = [(urljoin(url,a.get(‘href‘)),a.text) for a in indexList if a]
        indexs +=index
    return indexs

def novel(url):
    tmpFiles = []
    tasks = []
    try:
        indexs = index(url)
        tmpDir = os.path.join(os.getcwd(),‘tmp‘)
        if not os.path.exists(tmpDir):             #创建章节片段存放的临时目录
            os.mkdir(tmpDir)
        for i,info in enumerate(indexs):
            tmpFile = os.path.join(tmpDir,str(i))
            tmpFiles.append(tmpFile)
            task = Download(tmpFile,info)            #开启新线程下载章节内容
            task.setDaemon(True)
            task.start()
            tasks.append(task)
            if len(tasks) >= 20:                  #将线程总数控制在20个以内,如果线程过多会导致程序崩溃
                while len([task for task in tasks if task.isAlive()]):
                    print( ‘进度: {} / {}‘.format(i+1-len([task for task in tasks if task.isAlive()]),len(indexs)))  #显示下载进度
                    time.sleep(2)
                tasks = []
            if i == len(indexs) - 1:
                while len([task for task in tasks if task.isAlive()]):
                    print( ‘进度: {} / {}‘.format(len(indexs) - len([task for task in tasks if task.isAlive()]),len(indexs)))
                    time.sleep(2)
        print( ‘进度: {} / {}‘.format(len(indexs),len(indexs)))
        print(‘开始整合......‘)
        merge(tmpFiles,os.path.join(os.getcwd(),title+‘.txt‘))
        print(‘下载成功!‘)
    except Exception as ex:
        print(ex)
        print(‘下载失败!‘)
        sys.exit()
def main(argv):
    try:
        novel(argv[0])
    except KeyboardInterrupt as kbi:            #使用<C-c>中断下载后仍然能将已下载的章节合并
        tmpDir = os.path.join(os.getcwd(),‘tmp‘)
        if os.path.exists(tmpDir):
            tmpFiles = [os.path.join(tmpDir,tfile) for tfile in os.listdir(tmpDir) if os.path.isfile(os.path.join(tmpDir,tfile))]
            print(‘开始整合不完整的下载......‘)
            try:
                merge(tmpFiles,os.path.join(os.getcwd(),‘不完整文档.txt‘))
                if os.path.exists(os.path.join(os.getcwd(),‘不完整文档.txt‘)):
                    print(‘部分章节下载成功!‘)
                else:
                    print(‘下载失败!‘)
            except:
                print(‘下载失败!‘)
                sys.exit()
            os.rmdir(tmpDir)
        else:
            print(‘下载失败!‘)
            sys.exit()
    if os.path.exists(os.path.join(os.getcwd(),‘tmp‘)):
        os.rmdir(os.path.join(os.getcwd(),‘tmp‘))

if __name__ == "__main__":
    if len(sys.argv) > 1:
        main(sys.argv[1:])
    #http://www.lueqiu.com/

截图:

时间: 2024-10-12 19:18:52

Python3利用BeautifulSoup4抓取站点小说全文的代码的相关文章

对比使用Charles和Fiddler两个工具及利用Charles抓取https数据(App)

原文:https://www.cnblogs.com/qingqing-919/p/8444816.html 对比使用Charles和Fiddler两个工具及利用Charles抓取https数据(App) 实验目的:对比使用Charles和Fiddler两个工具 实验对象:车易通App,易销通App 实验结果: 1.     接口数据呈现方式对比: (1) Charles树状结构呈现于屏幕,清晰易区分 (2)Fiddler默认按时间倒叙呈现所有接口数据,不易区分 个人觉得图形界面上Charles

python3用BeautifulSoup抓取id=&#39;xiaodeng&#39;,且正则包含‘elsie’的标签

# -*- coding:utf-8 -*- #python 2.7 #XiaoDeng #http://tieba.baidu.com/p/2460150866 #使用多个指定名字的参数可以同时过滤tag的多个属性 from bs4 import BeautifulSoup import urllib.request import re #如果是网址,可以用这个办法来读取网页 #html_doc = "http://tieba.baidu.com/p/2460150866" #req

利用Fiddler抓取websocket包

一.利用fiddler抓取websockt包 打开Fiddler,点开菜单栏的Rules,选择Customize Rules... 这时会打开CustomRules.js文件,在class Handlers中加入以下代码 static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToString()

利用wireshark抓取Telnet的用户名和密码

使用wireshark抓取Telnet   目标ip地址(telnet  192.168.88.1 ) 1,首先打开wireshark,然后选择网卡,点击开始. 2,为了在filter中输入telnet 或者输入(ip.dst == 目标ip地址 and  tcp.port== 23). 3,看下面的数据包,找到telnet  并且能够看到data:\r\n:如下图 4,接下来再看下面的数据包,就能看到明文用户名和密码了.如下图 这时候你就可以看到明文用户名的首字母x了,继续看下去你可以找到后面

利用RCurl抓取电影团购信息

1 抓取的网址是360团购 http://tuan.360.cn/bei_jing/c_0.html?kw=电影&pageno=1#tuanFilter 2 利用firefox的FireBug插件分析其源代码,如下所示: "//*/h3[@class='desc']" 匹配电影院名称 "//*/span [@class='discount']" 匹配原价 "//*/span [@class='price']" 匹配优惠价 "//

利用fiddler抓取Android app数据包

前言 做Android开发的朋友经常需要做网络数据的获取和提交表单数据等操作,然而对于调试程序而言,很难知道我们的数据到底是以怎样的形式发送的,是否发送成功,如果发送失败有是什么原因引起的.fiddler工具为我们提供了很方便的抓包操作,可以轻松抓取浏览器的发出的数据,不管是手机APP,还是web浏览器,都是可以的. 什么是fiddler 百度百科上是这样说的:Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的"进出&quo

爬虫技术(四)-- 简单爬虫抓取示例(附c#代码)

这是我的第一个爬虫代码...算是一份测试版的代码.大牛大神别喷... 通过给定一个初始的地址startPiont然后对网页进行捕捉,然后通过正则表达式对网址进行匹配. List<string> todo :进行抓取的网址的集合 List<string> visited :已经访问过的网址的集合 下面实现的是,给定一个初始地址,然后进行爬虫,输出正在访问的网址和已经访问的网页的个数. 需要注意的是,下面代码实现的链接匹配页面的内容如图一.图二所示: 图一: 图二: 简单代码示范如下:

抓取天涯文章的蜘蛛代码,刚经过更新(因为天涯页面HTML代码变化)

#_*_coding:utf-8-*- import urllib2 import traceback import codecs from BeautifulSoup import BeautifulSoup def openSoup(url,code): page = urllib2.urlopen(url) soup = BeautifulSoup(page,fromEncoding=code)#,fromEncoding="gb2312" #soup = BeautifulSo

一个Python3批量抓取站点图片的程序

边学边写代码,记录下来.这段代码用于批量抓取主站下所有子网页中符合特定尺寸要求的的图片文件,支持中断. 原理很简单:使用BeautifulSoup4分析网页,获取网页<a/>和<img/>元素,对<a/>集合反复弹栈入栈,对<img/>集合进行筛选下载. 具体代码如下:import os import sys import time import urllib.request from urllib.parse import urljoin,urlparse