Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >跨站数据

python自动下载小说

大家好呀,空虚且漫长的三天小长假终于过去了,,哈哈哈哈,又是一个愉快的周一
在这里插入图片描述
刚到公司还没坐下,我旁边的IOS同学就悄悄告诉我项目出了BUG,并给我投来了一个神秘的微笑。。。
在这里插入图片描述
在我吃完早餐,喝完开水,上完厕所之后,手终于没那么抖了,慢慢的打开电脑,才发现只是一个小问题。哈哈哈哈,花费一分钟解决。哎哟,可把我牛逼坏了
在这里插入图片描述
旁边的IOS同学凑过来,用他那不太飘准的普通发给我说:“兄die,上次那个爬图片的很好用啊,不过我这几天看图片看太多了,灵感倒是有很多,就是身体有点吃不消。最近迷上了看小说,可是正版的冲不起钱,盗版的广告又太多,你给我解决解决?”
我:“作为一个优雅的社畜,怎么能看盗版呢?朕瞧不起你这无耻之徒。发过来,朕先举报(保存)一手”
在这里插入图片描述
半小时后,IOS同学:“兄die,怎么样了,解决了吗”
我心想:卧槽,看入迷了,还没开始写,怎么办。
表面稳如老狗,答曰:“emmmmm,这个比较有技术难度,稍等一下,就快好了”
在这里插入图片描述
当然,小说要看,问题还是要解决。怎么才能只看自己想看的内容,去掉自己不想看的内容呢?心念电转,还是用爬虫吧,内容都拿下来,只保存自己想看的不就行了。说干就干。。。
书名《全职法师》,url在代码里
页面大概长这样:
在这里插入图片描述
爬虫三连:获取网页,解析网页,保存目标
随手写个第一版,将内容保存在文件里面,以title做文件名:

import queue
import requests
from lxml import etree as et
import re
import random
import time
import os

# 请求头
headers = {
    # 用户代理
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

USER_AGENT_LIST = [
    'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
    'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
    'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
    'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
    'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
    'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
    'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
    'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
]

# 保存小说文件
def save_file(dir,filename,content):
    # 如果目录不存在,则新建
    if not os.path.exists(dir):
        os.makedirs(dir)
    save_dir = dir+'/'+filename+'.txt'
    #注意:win系统默认新文件编码格式gbk,这里需指定utf-8编码
    with open(save_dir, 'w',encoding='utf-8') as f:
        f.write(content)
    print('ok')

def get_chapter_url(list_url, base_url, queue):
    # 获取页面信息
    response = requests.get(url=list_url, headers=headers)
    # 获取请求状态码
    code = response.status_code
    if code == 200:
        html = et.HTML(response.content)
        # 获取该小说章节list
        chapter_url = html.xpath('//*[@id="list"]/dl/dd/a/@href')[9:40]
        k = 1
        for i in chapter_url:
            #组装小说章节url
            page_url = base_url + i
            #将小说章节url+章节编号入队
            queue_element = page_url, str(k)
            queue.put(queue_element)
            k = k + 1

def get_detail_html(queue):
    while not queue.empty():
        #休息一下,太快会503.等待时长可根据实际情况调节,你可以在503的边缘疯狂试探
        time_num = 5
        time.sleep(time_num)
        # Queue队列的get方法用于从队列中提取元素
        queue_element = queue.get()
        queue.task_done()
        # 获取章节url
        page_url = queue_element[0]
        # 获取章节编号
        chapter_num = queue_element[1]
        headers = {
            # 从代理列表随机获取代理
            'User-Agent': random.choice(USER_AGENT_LIST)
        }
        response = requests.get(url=page_url, headers=headers)
        response.encoding = "utf-8"
        # 请求状态码
        code = response.status_code
        if code == 200:
            html = et.HTML(response.content)
            # 获取该章小说title
            title = html.xpath('//h1/text()')[0]
            # 获取该章小说内容
            r = html.xpath('//*[@id="content"]/text()')
            content = ''
            for i in r:
                # 正则匹配,去除干扰字符,只保留汉字和数字
                #\u标识unicode编码,u不能大写;之后跟一个十六进制,表示相应字符对应的unicode值,十六进制中英文不区分大小写
                #data = re.sub(u"([^\u4E00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])","",i)
                content = content + i
            # 去除两端空格
            title = title.strip()
            content = content.strip()
            #保存文件
            save_file(save_dir, title, content)
        else:
            print(code)
        print(title)

# 主函数
if __name__ == "__main__":
    # 小说章节基地址
    base_url = 'https://www.biqugecom.com'
    # 小说章节列表页地址
    list_url = 'https://www.biqugecom.com/0/15/'
    #文件保存目录,自由设置,开心就好a
    save_dir = os.path.abspath('../quanzhifashi/')

    # 用Queue构造一个先进先出队列
    urls_queue = queue.Queue()
    #获取章节url列表
    get_chapter_url(list_url,base_url,urls_queue)
    #获取章节内容,存入数据库
    get_detail_html(urls_queue)

    print('the end!')

略一运行:
在这里插入图片描述
保存下来的小说:
在这里插入图片描述
过了一会儿,IOS:“老哥,你这个txt让我很为难啊,用户体验不怎么的,优化一下?”
沉思五秒后,我:“那我给你写成接口,你自己随便写一个APP,调我的接口怎么样?这样的话,界面你可以自己DIY,还能根据你的内裤颜色换小说背景色。”
IOS:“这个好,这个好,虽然我不怎么穿内裤,嘿嘿”
我:“。。。。。。。。。。。”
在这里插入图片描述
niubi要吹,代码还是要写。数据库那么多,选什么牌子呢?数据库技术哪家强,mysql数据库帮你忙,好用开源是真香
先安装一个mysql驱动吧:pip3 install mysql-connector
建个表保存小说章节编号,title和正文内容:

# Host: localhost  (Version: 5.7.26)
# Date: 2020-01-06 11:28:42
# Generator: MySQL-Front 5.3  (Build 4.234)

/*!40101 SET NAMES utf8 */;

#
# Structure for table "novel"
#

DROP TABLE IF EXISTS `novel`;
CREATE TABLE `novel` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `chapter_num` int(11) DEFAULT NULL COMMENT '章节编号',
  `title` varchar(20) NOT NULL DEFAULT '0' COMMENT '章节标题',
  `content` varchar(15000) DEFAULT NULL COMMENT '章节内容',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=utf8;

然后写个方法存数据,抱着试一试的心态,点击运行,得如下结果:
在这里插入图片描述
打开mysql一看。
在这里插入图片描述
呵,我可真是天选之子
在这里插入图片描述
完整代码:

import queue
import requests
from lxml import etree as et
import re
import random
import time
import os
import mysql.connector

# 请求头
headers = {
    # 用户代理
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

#用户代理列表
USER_AGENT_LIST = [
    'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
    'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
    'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
    'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
    'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
    'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
    'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
    'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
]

# 保存小说文件
def save_file(dir,filename,content):
    # 如果目录不存在,则新建
    if not os.path.exists(dir):
        os.makedirs(dir)
    save_dir = dir+'/'+filename+'.txt'
    #注意:win系统默认新文件编码格式gbk,这里需指定utf-8编码
    with open(save_dir, 'w',encoding='utf-8') as f:
        f.write(content)
    print('ok')

# 插入数据库
def insert_data(chapter_num, title, content):
    conn = mysql.connector.connect(user='root', password='root', database='test')
    cursor = conn.cursor()
    try:
        cursor.execute('insert into novel (chapter_num, title, content) values (%s, %s, %s)', [chapter_num, title, content])
        conn.commit()
    except Exception as e:
        print('Error:', e)
    finally:
        cursor.close()
        conn.close()

def get_chapter_url(list_url, base_url, queue):
    # 获取页面信息
    response = requests.get(url=list_url, headers=headers)
    # 获取请求状态码
    code = response.status_code
    if code == 200:
        html = et.HTML(response.content)
        # 获取该小说章节list
        chapter_url = html.xpath('//*[@id="list"]/dl/dd/a/@href')[9:40]
        k = 1
        for i in chapter_url:
            #组装小说章节url
            page_url = base_url + i
            #将小说章节url+章节编号入队
            queue_element = page_url, str(k)
            queue.put(queue_element)
            k = k + 1

#获取章节内容,存入数据库
def get_detail_html(queue):
    while not queue.empty():
        #休息一下,太快会503.等待时长可根据实际情况调节,你可以在503的边缘疯狂试探
        time_num = 5
        time.sleep(time_num)
        # Queue队列的get方法用于从队列中提取元素
        queue_element = queue.get()
        queue.task_done()
        # 获取章节url
        page_url = queue_element[0]
        # 获取章节编号
        chapter_num = queue_element[1]
        headers = {
            # 从代理列表随机获取代理
            'User-Agent': random.choice(USER_AGENT_LIST)
        }
        response = requests.get(url=page_url, headers=headers)
        response.encoding = "utf-8"
        # 请求状态码
        code = response.status_code
        if code == 200:
            html = et.HTML(response.content)
            # 获取该章小说title
            title = html.xpath('//h1/text()')[0]
            # 获取该章小说内容
            r = html.xpath('//*[@id="content"]/text()')
            content = ''
            for i in r:
                content = content + i
            # 去除两端空格
            title = title.strip()
            content = content.strip()
            #插入数据库
            insert_data(chapter_num, title, content)
            #保存文件
            #save_file(save_dir, title, content)
        else:
            print(code)
        print(title)

# 主函数
if __name__ == "__main__":
    # 小说章节基地址
    base_url = 'https://www.biqugecom.com'
    # 小说章节列表页地址
    list_url = 'https://www.biqugecom.com/0/15/'
    #文件保存目录,自由设置,开心就好a
    save_dir = os.path.abspath('../quanzhifashi/')

    # 用Queue构造一个先进先出队列
    urls_queue = queue.Queue()
    #获取章节url列表
    get_chapter_url(list_url,base_url,urls_queue)
    #获取章节内容,存入数据库
    get_detail_html(urls_queue)

    print('the end!')

又过了一会儿,IOS同学:“兄die,你这个有点慢啊,下载一章还要休息几秒”
我:“因为这个网站有限制,太快了会503,再说就算你一目十行也看不了那么快吧”
IOS:“看小说倒是不影响,就是你这样的代码影响我吹牛逼”
我:“emmmmm,那我搭建个IP池,然后给你改成多线程”
在这里插入图片描述
当朕准备搭建IP池的时候,产品经理的头像突然闪了起来。
只见消息列表里面躺着一个需求文档,并附文:
在这里插入图片描述
emmmmmm,溜了溜了。

The end !

学到了就要教人,赚到了就要给人
薪火相传,方能生生不息

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: 阿里巴巴向全社会开放黑科技:“泡在水里”的服务器

下一篇: 这6个编程语言排行榜,据说全都知道的人不足1% | 年终榜单大盘点

精华推荐