吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4316|回复: 20
收起左侧

[Python 转载] 萌新写某小说网站爬虫的经历

[复制链接]
Zeaf 发表于 2020-3-31 22:52
本帖最后由 Zeaf 于 2020-3-31 23:42 编辑

52网友想爬某小说...看着不是很难,于是简要分析了一下。【网站链接屏蔽~】
首先进入网站主页面,F12分析一下进入具体某个小说的链接(这里特指网站的推荐榜)
https://imgchr.com/i/GlELTA
可以看见特征比较明显,提取之后只要补全链接就行了
[Python] 纯文本查看 复制代码
url1s=[]
urls = re.findall('<p class="p2"><a href="(.*?)">.*?</a></p>', html)  # 用正则表达式获得所有文章网址
for url in urls:
    url='网站链接'+url
    url1s.append(url)

进入以后分析标题和章节(以下仅论述章节)

可以看到也是特征较明显,补全链接就行
[Python] 纯文本查看 复制代码
    url2s = re.findall('<li><a href="(.*?.html)">.*?</a></li>', html)  # 用正则表达式获得本页章节网址
    for url2 in url2s:
        time.sleep(2)
        url2 = '网站链接'+url2 

之后如何提取文本呢?

如图可知’    ‘为特征,以此进行提取即可
[Asm] 纯文本查看 复制代码
re.findall('    (.*?)<br/>', html)

然后重头戏来了,多页爬取怎么办?
分析一下每页的url规律
/10/10851/
/10/10851_2/#all
/10/10851_3/#all
很容易发现只是改了后面而已,假设页码为i,那么就得修改为’/10/10851‘+‘_’+str(i)+'/#all'
那么接下来的问题就是如何修改字符串了,我的思路是直接切片添加或者转为字符串再修改还原(麻烦)
[Python] 纯文本查看 复制代码
url=url1[:-1]+'_'+str(i)+'/#all'#补全网址
或者
url_list=list(url1)
url_list[-1]='_'+str(i)+'/#all'
url1=''.join(url_list)
url1 = '网页链接'+url1

大功告成!?
当我也以为完成的时候运行了一下发现到最后一页时会无限循环...
比如只有/10/10851_16/#all,但是爬虫会一直运行/10/10851_17/#all、/10/10851_18/#all等,因为这些页面都包含最新章节提醒,实际上没有需要爬取的内容
于是我加了一个判断(最新章节提醒有5章)
[Python] 纯文本查看 复制代码
if len(url3s) > 10:#防止无限循环,因为有最新章节存在
else:
    print('本书保存完成!')
    break#前面我弄了个循环,具体看完整源码

之所以是10,我考虑到如果恰好最后一页就是最新章节,加上推荐的最新章节就是10个url,只有多于10个才说明有新内容
到此差不多就完成了,该网站似乎支持无停顿爬取...体验还行

下附基于特定书籍网页的完整源码:
[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 31 15:34:39 2020

@author: Zeaf
"""

import requests  # 导入requests库
import re  # 导入正则表达式库
import os # 保存文件
import time # 用来停顿
#伪装
user = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
#自定义书籍爬取和停顿时间
url1=input('请输入所要爬取书籍的网址:')#这里可以再去爬推荐榜什么的来替换
stop=int(input('请输入停顿时间(整数):'))
#多页爬取
i=1
while True:
    try:
        url=url1[:-1]+'_'+str(i)+'/#all'#补全网址
        response = requests.get(url,headers=user)#模拟访问
        response.encoding = response.apparent_encoding#防止乱码
        html = response.text  # 用文本显示访问网页得到的内容            
        url3s = re.findall('<li><a href="(.*?)">.*?</a></li>', html)  # 用正则表达式获得本页章节网址
        dir_name=re.findall('<h1>(.*?)</h1>', html)[-1]#正则提取书名,这里实际上提取到两个,选择一个
        print('正在保存的书籍为:'+dir_name)
        if not os.path.exists(dir_name):  # 判断文件夹是否存在,如果不存在:
            os.mkdir(dir_name)#创建文件夹
        if len(url3s) > 10:#防止无限循环,因为有最新章节存在
            for url3 in url3s:#遍历本页所有章节网址
                time.sleep(stop)#暂停,防止频繁被发现
                url3 = '网页链接'+url3#补全网址
                response = requests.get(url3,headers=user)
                response.encoding = response.apparent_encoding#防止乱码
                html = response.text  
                texts_in = re.findall('    (.*?)<br/>', html)#提取文本内容
                text_true = ''#创建空字符串
                for texts in texts_in:#遍历文本内容
                    text_true=text_true+texts+'\n'#\n换行排版
                file_name = re.findall('<h1>(.*?)</h1>', html)[-1]#提取章节名
                with open(dir_name + '/'  + file_name+'.txt', 'wb') as f:#str(i)方便排序,不想要可去掉
                    f.write(text_true.encode())#encode()用于str转为bytes,py3.0必备,py2.0无需
                    f.write('\n'.encode())#防止覆盖
                    f.close()#关闭文件
                print('成功保存一章!')
            print('成功保存第'+str(i)+'页!') 
            i+=1#为进入下一页做准备
        else:
            print('本书保存完成!')
            break
    except:
        print('失败!')
        break#跳出循环

实际上还能优化...但现在感觉也足够用了,反正能够多开
实际上还可以加一个搜索什么的,自动爬取所有搜索结果的书籍...
等等,只要能够爬一本书,其它都不是问题~

免费评分

参与人数 1热心值 +1 收起 理由
麦田孤望者 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Zeaf 发表于 2020-4-3 21:00
本帖最后由 Zeaf 于 2020-4-3 21:09 编辑

又改进了一下代码...
可选择版:
[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
"""
Created on Fri Apr  3 18:55:02 2020

@author: Zeaf
"""
import requests  # 导入requests库
import re  # 导入正则表达式库
import os # 保存文件
import time # 用来停顿
os.system('吾爱破解@Zeaf')
user = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
def get_book(url_in):
    number=1
    while True:
        try:
            url=url_in[:-1]+'_'+str(number)+'/#all'#补全网址
            response = requests.get(url,headers=user)#模拟访问
            response.encoding = response.apparent_encoding#防止乱码
            html = response.text  # 用文本显示访问网页得到的内容            
            url3s = re.findall('<li><a href="(.*?)">.*?</a></li>', html)  # 用正则表达式获得本页章节网址
            dir_name=re.findall('<h1>(.*?)</h1>', html)[-1]#正则提取书名,这里实际上提取到两个,选择一个
            print('正在保存的书籍为:'+dir_name)
            if not os.path.exists(dir_name):  # 判断文件夹是否存在,如果不存在:
                os.mkdir(dir_name) # 创建文件夹
            if len(url3s) > 10: # 防止无限循环,因为有最新章节存在
                for url3 in url3s: # 遍历本页所有章节网址
                    time.sleep(stop) # 暂停,防止频繁被发现
                    url3 = 'https://m.xipu8.com'+url3 # 补全网址
                    response = requests.get(url3,headers=user)
                    response.encoding = response.apparent_encoding
                    html = response.text  
                    texts_in = re.findall('    (.*?)<br/>', html)#提取文本内容
                    text_true = '' # 创建空字符串
                    for texts in texts_in: # 遍历文本内容
                        text_true=text_true+texts+'\n' # \n换行排版
                    file_name = re.findall('<h1>(.*?)</h1>', html)[-1] # 提取章节名
                    with open(dir_name + '/'  + file_name+'.txt', 'wb') as f: # str(number)方便排序,不想要可去掉
                        f.write(text_true.encode()) # encode()用于str转为bytes,py3.0必备,py2.0无需
                        f.write('\n'.encode()) # 换行
                        f.close() # 关闭文件,可去除,with open自带关闭功能
                    print('成功保存一章!')
                print('成功保存第'+str(number)+'页!') 
                number+=1 # 为进入下一页做准备
            else:
                print('本书保存完成!')
                break
        except:
            print('失败!')
            break # 跳出循环    
        
pages = int(input('爬取页数:'))
stop = int(input('停顿时间(整数):'))
goal = int(input('需要爬取的排行榜(总推荐榜为1,最新入库为2,总点击榜为3):'))
if goal == 1:
    #爬取总推荐榜
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/allvote_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            get_book(url_in) # 调用之前写好的函数
        print('已爬取完排行榜一页!')
elif goal == 2:
    #爬取最新入库
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/postdate_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            get_book(url_in) # 调用之前写好的函数
            print('已爬取完排行榜一页!')
elif goal == 3:
    #爬取总点击榜
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/allvisit_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            get_book(url_in) # 调用之前写好的函数
            print('已爬取完排行榜一页!')
else:
    print('输入有误!')
time.sleep(3)#暂停3s查看结果
print('完成,3s后自动关闭。')

多线程版:
[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
"""
Created on Fri Apr  3 20:33:49 2020

@author: Zeaf
"""

import requests  # 导入requests库
import re  # 导入正则表达式库
import os # 保存文件
import time # 用来停顿
import threading    #导入多线程库
os.system('吾爱破解@Zeaf')
print('@Author Zeaf')
user = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
def get_book(url_in, webname):
    number=1
    while True:
        try:
            url=url_in[:-1]+'_'+str(number)+'/#all'#补全网址
            response = requests.get(url,headers=user)#模拟访问
            response.encoding = response.apparent_encoding#防止乱码
            html = response.text  # 用文本显示访问网页得到的内容            
            url3s = re.findall('<li><a href="(.*?)">.*?</a></li>', html)  # 用正则表达式获得本页章节网址
            dir_name=re.findall('<h1>(.*?)</h1>', html)[-1]#正则提取书名,这里实际上提取到两个,选择一个
            print('正在保存的书籍为:'+dir_name)
            if not os.path.exists(webname+'/'+dir_name):  # 判断文件夹是否存在,如果不存在:
                os.mkdir(webname+'/'+dir_name) # 创建文件夹
            if len(url3s) > 10: # 防止无限循环,因为有最新章节存在
                for url3 in url3s: # 遍历本页所有章节网址
                    time.sleep(stop) # 暂停,防止频繁被发现
                    url3 = 'https://m.xipu8.com'+url3 # 补全网址
                    response = requests.get(url3,headers=user)
                    response.encoding = response.apparent_encoding
                    html = response.text  
                    texts_in = re.findall('    (.*?)<br/>', html)#提取文本内容
                    text_true = '' # 创建空字符串
                    for texts in texts_in: # 遍历文本内容
                        text_true=text_true+texts+'\n' # \n换行排版
                    file_name = re.findall('<h1>(.*?)</h1>', html)[-1] # 提取章节名
                    with open(webname+'/'+dir_name + '/'  + file_name+'.txt', 'wb') as f: # str(number)方便排序,不想要可去掉
                        f.write(text_true.encode()) # encode()用于str转为bytes,py3.0必备,py2.0无需
                        f.write('\n'.encode()) # 换行
                        f.close() # 关闭文件,可去除,with open自带关闭功能
                    print('成功保存一章!')
                print('成功保存第'+str(number)+'页!') 
                number+=1 # 为进入下一页做准备
            else:
                print('本书保存完成!')
                break
        except:
            print('失败!')
            break # 跳出循环    
        
def get_allvote():
    #爬取总推荐榜
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/allvote_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            time.sleep(stop)
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            webname = '总推荐榜'
            if not os.path.exists(webname):  # 判断文件夹是否存在,如果不存在:
                os.mkdir(webname) # 创建文件夹
            get_book(url_in, webname) # 调用之前写好的函数
        print('已爬取完总推荐榜一页!')
    print('第一线程运行完毕!')
    
def get_postdate():
    #爬取最新入库
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/postdate_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            time.sleep(stop)
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            webname = '最新入库'
            if not os.path.exists(webname):  # 判断文件夹是否存在,如果不存在:
                os.mkdir(webname) # 创建文件夹
            get_book(url_in, webname) # 调用之前写好的函数
        print('已爬取完最新入库一页!')
    print('第二线程运行完毕!')
    
def get_allvisit():
    #爬取总点击榜
    for i in range(1,pages+1):    
        response = requests.get('https://m.xipu8.com/top/allvisit_'+str(i)+'/', headers=user)  # 用requests库的get函数访问总网页,用headers进行伪装,获得源码
        response.encoding = response.apparent_encoding # 防止乱码
        html = response.text  # 用文本显示访问网页得到的内容
        urls = re.findall('<a href="(/.*?/)" class="blue">', html)  # 用正则表达式获得本页所有文章网址
        for url in urls: # 遍历获取到的文章链接
            time.sleep(stop)
            url_in = 'https://m.xipu8.com/'+url # 补全本页所有文章链接
            webname = '总点击榜'
            if not os.path.exists(webname):  # 判断文件夹是否存在,如果不存在:
                os.mkdir(webname) # 创建文件夹
            get_book(url_in, webname) # 调用之前写好的函数
        print('已爬取完总点击榜一页!')
    print('第三线程运行完毕!')

pages = int(input('爬取页数:'))
stop = int(input('停顿时间(整数):'))
t1 = threading.Thread(target=get_allvote)    #第一个线程
t2 = threading.Thread(target=get_postdate)    #第二个线程
t3 = threading.Thread(target=get_allvisit)    #第三个线程
t1.start()    #启动第一个线程
t2.start()   #以此类推
t3.start()
xxoopp 发表于 2020-4-1 10:13
Zeaf 发表于 2020-4-1 09:49
不是很清楚其中原理...
这两个功能重复了吗

with open() as f里面自带了关闭文档功能所以不需要再使用close()了
 楼主| Zeaf 发表于 2020-3-31 22:55
本帖最后由 Zeaf 于 2020-3-31 23:07 编辑

吐了...不是链接可以自动加载嘛
看来非得有后缀才行
xuegaoxiansen 发表于 2020-3-31 23:19
可以的,爬的不错
Wa19970322 发表于 2020-4-1 00:49
厉害了我的哥
xxoopp 发表于 2020-4-1 01:00
48行用了with open不需要再用close了
qi511212 发表于 2020-4-1 02:09
又使我增加了知识
 楼主| Zeaf 发表于 2020-4-1 09:49
xxoopp 发表于 2020-4-1 01:00
48行用了with open不需要再用close了

不是很清楚其中原理...
这两个功能重复了吗
 楼主| Zeaf 发表于 2020-4-1 10:16
xxoopp 发表于 2020-4-1 10:13
with open() as f里面自带了关闭文档功能所以不需要再使用close()了

好的,多谢大佬指点
xxoopp 发表于 2020-4-1 11:24
Zeaf 发表于 2020-4-1 10:16
好的,多谢大佬指点

没有,不是大佬,建议你把单个功能比如访问页面 读取什么都分别写成不同的函数,方便修改和维护
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 23:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表