xiaomayi2012 发表于 2020-10-15 20:58

知轩藏书精校小说网全站爬虫

本帖最后由 xiaomayi2012 于 2021-6-6 21:22 编辑

这个爬虫是去年写的爬取 知轩藏书 网的一个爬虫,看论坛也有人分享这个网站的爬虫,我这个是去年7月份写的,代码有些乱,但主要功能都有,当时为了建小说站搞的,也没搞起来,今天整理硬盘时发现的,所以今天就分享出来,供大家交流学习,代码写的不是很严谨,很多冗余,可以根据喜好自行增删,大佬可以飘过~!以下代码仅供学习交流!废话不多说先上图:




本爬虫是直接爬取全站包括 小说简介 、图片、小说压缩包, 不能单独下载某一本小说,自己也懒得写了,需要的可以自己再添加,今天试了试代码可以正常运行,环境用的python 3.7 ,下面代码奉上:
【注意】:运行程序的时候一定要切换到程序根目录运行,根据下方的结构图建目录。
0、文件结构:

E:/zxcs
│——zxcs.py

└─common
    │ —— config.ini
    │ —— DeHTMLParser.py
    │


1、主程序:zxcs.py
import requests
import random
from lxml import etree
from common.DeHTMLParser import html_toText
import os
import time
import re


base_url = 'http://www.zxcs.me/sort/{}'

page = "/page/{}"
user_agent_list = [
    "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
]
UA = random.choice(user_agent_list)
HEADERS = {'User-Agent': UA}

# 简单封装网络请求操作

def get_requests(url):
    global NETWORK_STATUS
    NETWORK_STATUS = True# 判断状态变量
    try:
      req = requests.get(url, headers=HEADERS, timeout=20)
      if req.status_code == 200:
            html = req.text
            return html
    except requests.exceptions.Timeout:
      NETWORK_STATUS = False# 请求超时改变状态
      if not NETWORK_STATUS:
            '''请求超时'''
            for i in range(1, 10):
                print('请求超时,第%s次重复请求' % i)
                req = requests.get(url, headers=HEADERS, timeout=5)
                if req.status_code == 200:
                  html = req.text
                  return html
    return -1


# 获取各分类列表页中的总页数

def getPageTotal(cates):
    #base_url = "http://www.zxcs.me/sort/25/"
    req = get_requests(base_url.format(cates))
    selector = etree.HTML(req)
    page = selector.xpath("//*[@id='pagenavi']/a/@href")[-1].split('/')[-1]# 获取每个分类下的总页数

    return page

# 获取每个分类下每页内容

def getPage(category, pageIdex):
    req = get_requests(base_url.format(category) + page.format(str(pageIdex)))
    return req


# 获取列表中文章的url

def getList(cates, pageIdex):
    req = getPage(cates, pageIdex)
    selector = etree.HTML(req)
    url_list = selector.xpath("//*[@id='plist']/dt/a/@href")

    return url_list


# 获取下载链接

def get_downUrl(url):
    link_id = url.split('/')[-1]# 通过传入的文章地址截取网址中的文章id
    req = get_requests("http://www.zxcs.me/download.php?id={}".format(link_id))
    selector = etree.HTML(req)
    d_url = selector.xpath("//span[@class='downfile']/a/@href")
    return d_url


# 下载小说

def saveRAR(url,fileName):
    print("开始下载",fileName,"小说...\n")
    rar_name = url.split('/')[-1]# 截取网址中小说名称
    names = fileName + '/' + str(rar_name) #组合下载路径
    start = time.time()#开始时间
    size = 0
    req = requests.get(url,stream = True,headers=HEADERS)
    chunk_size = 1024 #每次下载的数据大小
    content_size = int(req.headers['content-length'])#总大小

    if req.status_code==200:
      print('[文件大小]:%0.2f MB' %(content_size / chunk_size /1024))#换算单位并print()
      with open(names,'wb') as f:
            for d in req.iter_content(chunk_size=chunk_size): # 获取请求的原始响应
                f.write(d)
                size += len(d)#已下载文件大小
                print('\r'+'[下载进度]:%s %.2f%%' % ('>'*int(size*50/ content_size),float(size/ content_size*100)),end='')
            f.close()

      end = time.time()
      print('\n',"小说下载完成!用时%.2f秒"%(end-start))

# 保存内容简介

def saveBrief(content,name):
    fileName = name + "/" + name + ".txt"
    f = open(fileName,"w+")
    print("正在偷偷保存小说简介",fileName)


    f.write(content)
# 保存内容页中图片到本地

def saveImg(imgUrl,fileName):
    name = imgUrl.split('/')[-1]
    req = requests.get(imgUrl).content
    if name.endswith(".jpg"):
      names = fileName + "/" +str(name)
    else:
      names = fileName+"/"+str(name.split('?'))

    f = open(names,'wb')
    f.write(req)
    print("正在悄悄的保存小说图片",name)
    f.close()


# 创建新目录

def mkdir(path):
    path = path.strip()
    # 判断路径是否存在
    # 存在   True
    # 不存在   False
    isExists=os.path.exists(path)
    # 判断结果
    if not isExists:
      # 如果不存在则创建目录
      print ("正在新建名为",path,'的文件夹')
      # 创建目录操作函数
      os.makedirs(path)
      return True
    else:
      # 如果目录存在则不创建,并提示目录已存在
      print("名为",path,'的文件夹已经创建!')
      return False


# 获取详情页内容并返回一个列表

def getContent(url):
    cont = []
    req = get_requests(url)
    selector = etree.HTML(req)
    title = selector.xpath("//*[@id='content']/h1/text()")# 标题
    category = selector.xpath("//*[@class='date']//a/text()") #分类
    if len(selector.xpath("//*[@class='date']//a/text()"))>=3:
      tags = selector.xpath("//*[@class='date']//a/text()") #分类
    else:
      tags ="暂无"
    if len(selector.xpath("//*[@id='content']/a/img/@src"))>0:
      image = selector.xpath("//*[@id='content']/a/img/@src") # 图片
    elif len(selector.xpath("//*[@id='content']/img/@src"))>0:
      image = selector.xpath("//*[@id='content']/img/@src") # 图片
    elif len(selector.xpath("//*[@id='content']/p/img/@src"))>0:
      image = selector.xpath("//*[@id='content']/p/img/@src")
    else:
      image = selector.xpath("//*[@id='content']/p/a/img/@src")# 图片

    # print(image)
    text_info = selector.xpath("//*[@id='content']//p")# 获取内容页文本
    div_str = etree.tostring(text_info)# 获取id中的html代码
    text = html_toText(div_str).strip().replace(' ', '')# 调用外部工具类提取html中文本
    text = "".join(text.split("\xa0")) #去掉特殊字符\xa0

    cont.append(title)
    cont.append(image)
    cont.append(text)
    cont.append(category)
    cont.append(tags)
    cont.append(get_downUrl(url))
    return cont


# 保存一篇文章内容信息
'''
contents 小说标题
contents 小说封面图
contents 小说简介
contents 小说分类
contents 小说下载地址
'''
def saveInfo(category,pageIndex):
    number = 1
    for ls in getList(category,pageIndex):
      contents = getContent(ls)
      mkdir(contents) # 以文件名创建文件夹目录
      saveImg(contents,contents) # 保存小说图片
      saveBrief(contents+"\n\n"+contents,contents) # 保存小说简介
      saveRAR(contents,contents) # 下载小说附件
      print("\n------ 分类ID为",category,"的第",str(number),"部小说信息保存完毕 ------\n")
      number +=1


# 启动爬虫开始爬取数据

def runSpider(pageId,categroy):
    num = getPageTotal(categroy)# 获取每个分类下总页数
    for i in range(int(pageId), int(num) + 1):
      saveInfo(categroy,i)
      print("\n[--------- 第",i,"页爬取完毕!---------]\n")


if __name__ == '__main__':
    c =
    # ss = get_page_total(base_url,23)
    # u = getList(23, 2)# 获取页面中文章url
    # t = getContent("http://www.zxcs.me/post/1568")
    # u = get_downUrl("http://www.zxcs.me/post/11610")
    # print(t)
    '''
    都市生活23    精校奇幻   38   精校灵异    41精校竞技    44
    精校武侠36    精校玄幻   39   精校历史    42精校游戏    45
    精校仙侠37    精校科幻   40   精校军事    43二次元      55
   
    '''
    f = open("common/config.ini", encoding = 'utf-8')
    print(f.read())
    category = input("请输入您要爬取的分类:")

    pages = input("\n请输入您要爬取的开始页:")
    if len(category)>0 and len(pages)>0:
      print("\n爬虫启动中...")
      time.sleep(2)
      print("开始爬取数据...",time.strftime("%Y/%m/%d %H:%M:%S"))
      time.sleep(3)
      runSpider(pages,category) # runSpider(页码,分类号)
      # for p in c:
      print("分类",category,"爬取完毕!")

2、过滤Html标签的工具类代码:common/DeHTMLParser.py
from html.parser import HTMLParser
from re import sub
from sys import stderr
from traceback import print_exc

"""
功能:将HTML提取为Text纯文本
"""
class DeHTMLParser(HTMLParser):
    def __init__(self):
      HTMLParser.__init__(self)
      self.__text = []

    def handle_data(self, data):
      text = data.strip()
      if len(text) > 0:
            text = sub('[ \t\r\n]+', ' ', text)
            self.__text.append(text + ' ')

    def handle_starttag(self, tag, attrs):
      if tag == 'p':
            self.__text.append('\n\n')
      elif tag == 'br':
            self.__text.append('\n')

    def handle_startendtag(self, tag, attrs):
      if tag == 'br':
            self.__text.append('\n\n')

    def text(self):
      return ''.join(self.__text).strip()

def html_toText(text):
    try:
      parser = DeHTMLParser()
      parser.feed(text.decode())
      parser.close()
      return parser.text()
    except:
      print_exc(file=stderr)
      return text

def main():
    text = r'''
      <div id="info">导演: <a href="https://www.xl720.com/thunder/director/%e9%99%88%e7%bf%8a%e6%81%92" rel="bookmark">陈翊恒</a><br /> 编剧: <a href="https://www.xl720.com/thunder/writers/%e9%99%88%e7%bf%8a%e6%81%92" rel="bookmark">陈翊恒</a> / <a href="https://www.xl720.com/thunder/writers/%e6%a2%81%e9%b8%bf%e5%8d%8e" rel="bookmark">梁鸿华</a> / <a href="https://www.xl720.com/thunder/writers/%e5%ba%b8%e6%9d%90" rel="bookmark">庸材</a> / <a href="https://www.xl720.com/thunder/writers/%e8%94%a1%e7%b4%a0%e6%96%87" rel="bookmark">蔡素文</a><br /> 主演: <a href="https://www.xl720.com/thunder/stars/%e6%9e%97%e8%80%80%e5%a3%b0" rel="bookmark">林耀声</a> / <a href="https://www.xl720.com/thunder/stars/%e9%a9%ac%e5%bf%97%e5%a8%81" rel="bookmark">马志威</a> / <a href="https://www.xl720.com/thunder/stars/%e5%85%83%e7%a7%8b" rel="bookmark">元秋</a> / <a href="https://www.xl720.com/thunder/stars/%e8%91%9b%e6%b0%91%e8%be%89" rel="bookmark">葛民辉</a> / <a href="https://www.xl720.com/thunder/stars/%e9%bb%8e%e7%be%8e%e8%a8%80" rel="bookmark">黎美言</a> / <a href="https://www.xl720.com/thunder/stars/%e6%9d%a8%e6%9f%b3%e9%9d%92" rel="bookmark">杨柳青</a> / <a href="https://www.xl720.com/thunder/stars/%e5%91%a8%e6%ae%b7%e5%bb%b7" rel="bookmark">周殷廷</a> / <a href="https://www.xl720.com/thunder/stars/%e6%9e%97%e6%9b%89%e9%9b%af" rel="bookmark">林曉雯</a> / <a href="https://www.xl720.com/thunder/stars/%e5%bc%a0%e6%b2%9b%e4%b9%90" rel="bookmark">张沛乐</a> / <a href="https://www.xl720.com/thunder/stars/%e9%83%91%e4%b8%bd%e8%8e%8e" rel="bookmark">郑丽莎</a> / <a href="https://www.xl720.com/thunder/stars/%e6%9d%8e%e5%ae%97%e5%bd%a5"
rel="bookmark">宗彥</a> / <a href="https://www.xl720.com/thunder/stars/%e7%bd%97%e5%a4%a9%e6%b1%a0" rel="bookmark">罗天池</a> / <a href="https://www.xl720.com/thunder/stars/%e6%9d%8e%e9%80%b8%e6%9c%97" rel="bookmark">李逸朗</a><br /> 类型: 动作<br /> 制片国家/地区: <a href="https://www.xl720.com/thunder/area/xianggang" rel="bookmark">香港</a><br /> 语言: 粤语<br /> 上映日期: <a href="https://www.xl720.com/thunder/years/2019" rel="bookmark">2019</a>-03-19(中国大陆) / 2019-03-21(香港)<br /> 片长: 108分钟<br /> 又名: 格斗吧 / We Are Legends</div>
    '''
    print(html_toText(text))


if __name__ == '__main__':
    main()


3.配置文件:common/config.ini
==========================================================================
*                                                                        *
* 都市生活 【23】    精校奇幻 【38】   精校灵异 【41】   精校竞技 【44】 *
*                                                                        *
* 精校武侠 【36】    精校玄幻 【39】   精校历史 【42】   精校游戏 【45】 *
*                                                                        *
* 精校仙侠 【37】    精校科幻 【40】   精校军事 【43】   二次元   【55】 *
*                                                                        *
*=========================================================================

花好s月圆 发表于 2020-10-15 22:00

还是用易语言post提交数据,更简单一点。

Natu 发表于 2020-10-16 00:58

Traceback (most recent call last):
File "zxcs.py", line 4, in <module>
    from common.DeHTMLParser import html_toText
ModuleNotFoundError: No module named 'common.DeHTMLParser'
大侠,请问这个故障怎么排除?

aas8588729 发表于 2020-10-15 21:40

牛!!!!!!!!!!!{:1_893:}

woflant 发表于 2020-10-15 22:12

感谢楼主分享
出现UnicodeDecodeError: 'gbk' codec can't decode byte 0x90 in position 169: illegal multibyte sequence错误
只需将
f = open("common/config.ini")
更改为
f = open("common/config.ini", encoding = 'utf-8')
即可

星辰一枚 发表于 2020-10-15 22:38

厉害了,感谢分享

玄非 发表于 2020-10-15 22:44

感谢分享

Natu 发表于 2020-10-15 23:30

爬虫横行……

Cypital 发表于 2020-10-15 23:30

厉害了,学习学习。

ciker_li 发表于 2020-10-16 08:48

学习学习
页: [1] 2 3 4
查看完整版本: 知轩藏书精校小说网全站爬虫