Python爬虫之爬取最新更新的小说网站


Posted in Python onMay 06, 2021

一、引言

这个五一假期自驾回老家乡下,家里没装宽带,用手机热点方式访问网络。这次回去感觉4G信号没有以前好,通过百度查找小说最新更新并打开小说网站很慢,有时要打开好多个网页才能找到可以正常打开的最新更新。为了躲懒,老猿决定利用Python爬虫知识,写个简单应用自己查找小说最新更新并访问最快的网站,花了点时间研究了一下相关报文,经过近一天时间研究和编写,终于搞定,下面就来介绍一下整个过程。

二、关于相关访问请求及应答报文

2.1、百度搜索请求

我们通过百度网页的搜索框进行搜索时,提交的url请求是这样的:

https://www.baidu.com/s?wd=搜索词&pn=10&rn=50

请求的url为https://www.baidu.com/s,带三个参数:

  • wd:搜索的关键词
  • pn:当前需要显示搜索结果记录在总搜索结果的序号,如总搜索有300条记录满足要求,现在要求显示第130条记录,则pn参数值设为130即可
  • rn:每页显示记录数,缺省为10条,可以自行设定,但如果设定超过50,则会强制显示为每页10条。

2.2、百度返回搜索结果

百度返回的搜索结果有多种方式确定,老猿认为如下方式最简单:
以搜索小说《青萍》为例来看其中的一个返回记录:

<h3 class="t"><a data-click="{
			'F':'778317EA',
			'F1':'9D73F1E4',
			'F2':'4CA6DE6B',
			'F3':'54E5243F',
			'T':'1620130755',
			'y':'FE7FF57A'}" 
			href="http://www.baidu.com/link?url=9LLa46B6hp69vJdLx6wOGfBpoS7BaRe8zV3oSNj_Vc2AxuU0Tz5Bl7CZlqNPobdw_BElAgaadA_HfCJMtADpyq" rel="external nofollow"  target="_blank">
			<em>青萍</em>最新章节,<em>青萍</em>免费阅读 - 大神小说网</a>
			</h3>

整个搜索返回的结果在一个h3的标签内,返回的搜索结果对应url在a标签内,具体url由href来指定。这里返回的url实际上是一个百度重定向的地址,可以通过打开该url访问对应网站,并通过返回响应消息获取真正网站的URL。

2.3、小说网站关于最新更新的展现及html报文格式

根据老猿分析,约占30%的小说网站关于最新更新章节的展现类似如下:

Python爬虫之爬取最新更新的小说网站

首先有类似“最新章节”或“最新更新”或“最近更新”等类似提示词,在该提示词后是显示最新章节的章节序号及章节名的一个链接,对应的报文类似如下:

<p>最新章节:<a href="/book/12/12938/358787.html" rel="external nofollow"  target="_blank">第729章 就是给你们看看的</a></p>

这个报文的特点是:

“最新章节”的文本信息与小说最新章节的链接在同一个父标签内。另外需要说明的是返回的章节url并不是绝对地址,而是小说网站的相对地址。

老猿对搜索小说查找最新章节都是基于以上格式的,因此实际上程序最终获取的小说网站只占了整个搜索结果的30%左右,不过对于看小说来说已经足够了。

三、实现思路及代码

3.1、根据url获取网站名

def getHostName(url):
    httpPost = url[10:]
    hostName = url[:10]+httpPost.split('/')[0]
    return hostName

3.2、根据百度返回搜索结果地址打开网站获取小说信息

基于2.3部分介绍的小说网站返回内容,我们来根据百度返回搜索结果的URL来打开对应小说网站,并计算从请求发起到响应返回的时间:

def getNoteInfo(url):
    """
    打开指定小说网页URL获取最新章节信息
    url:百度搜索结果指定的搜索匹配记录的url
    返回该URL对应的章节ID、打开耗时、网站真正URL、网站主机名、章节相对url、章节名
    
    """
    head = mkhead()
    start = time.time_ns()
    req = urllib.request.Request(url=url, headers=head)
    try:
        resp = urllib.request.urlopen(req,timeout=2)
        #根据响应头获取真正的网页URL对应的网站名
        hostName = getHostName(resp.url)
        text = resp.read()
        #网页编码有2种:utf-8和GBK
        pageText = text.decode('utf-8')
    except UnicodeDecodeError:
        pageText =  text.decode('GBK')
    except Exception as  e:
        errInf = f"打开网站 {url} 失败,异常原因:\n{e}\n" + '\n' + traceback.format_exc() + '\n'
        logPag(errInf, False)
        return None

    #最新章节的HTML报文类似: '<p>最新章节:<a href="/html/107018/122306672.html" rel="external nofollow" >第672章 天之关梁</a></p>'
    end = time.time_ns()
    soup = BeautifulSoup(pageText, 'lxml')
    # 根据最新章节的提示信息搜索最新章节
    result = soup.find_all(string=re.compile(r'最新更新[::]|最新章节[::]|最近更新[::]|最新[::]'))
    found = False
    for rec in result:
        recP = rec.parent
        pa = recP.a
        matchs = re.match(r'(?:最新更新|最新章节|最近更新|最新)[::]第(.+)章(.+)', recP.text)
        if not matchs:return None
        groups = matchs.groups()
        if matchs and pa is not None:
            found = True
            chapter = toInt(groups[0]) #章节序号
            chapterName = groups[1] #章节名
            chaperUrl = pa.attrs['href'] #章节相对URL
            break
    if not found:
        return None

    cost = (end - start) / 1000000  #网页打开耗时计算
    return (chapter,cost,resp.url,hostName,chaperUrl,chapterName)

注意:由于不同网站访问响应情况不一样,因此在打开网页时设定超时是很有必要的,这样可以避免访问缓慢的网站耽误整体访问时间。

3.3、获取小说网页绝对url地址

将返回信息中相对url和网站名结合拼凑网页的绝对url地址:

def getChapterUrl(noteInf):
    chapter, cost, url, hostName, chaperUrl, chapterName = noteInf
    if chaperUrl.strip().startswith('http'):return chaperUrl
    elif chaperUrl.strip().startswith('/'):return hostName.strip()+chaperUrl.strip()
    else:return hostName.strip()+'/'+chaperUrl.strip()

3.4、计算排序权重

根据搜索小说网页访问的信息计算排序权重,确保最新章节排在最前,相同章节访问速度最快网站排在最前。

def noteWeight(n):
#入参n为小说信息元组: chapter, cost, url, hostName, chaperUrl, chapterName
    ch,co = n[:2]
    w = ch * 100000 + min(99999, 100000 / co)
    return w

3.5、进行百度搜索并解析搜索结果访问小说网站最新更新

根据搜索词在百度执行搜索,并取最新章节且访问速度最快的前5个网站url进行输出:

def BDSearchUsingChrome(inputword,maxCount=150):
    """
    输出相关搜索结果中具有最新章节且访问速度最快的前5个网站url
    :param word: 搜索关键词,如小说名、小说名+作者名等
    :param maxCount: 最多处理的搜索记录数
    :return: None
    """
    #百度请求url类似:https://www.baidu.com/s?wd=青萍&pn=10&rn=50
    rn = 50 #每页50条记录
    #构建请求头模拟本机谷歌浏览器访问百度网页
    head = mkheadByHostForChrome('baidu.com')
    word =  urllib.parse.quote(inputword)
    urlPagePre = 'https://www.baidu.com/s?wd='+word+'&rn=50&'
    pageCount = int(0.999+maxCount/rn)
    validNoteInf = []
    seq = 0
    logPag("开始执行搜索...")
    for page in range(pageCount):
        pn = rn*page
        urlPage = urlPagePre+str(pn)
        pageReq = urllib.request.Request(url=urlPage, headers=head)
        pageResp = urllib.request.urlopen(pageReq,timeout=2)
        pageText = pageResp.read().decode()

        if pageResp.status == 200:
            soup = BeautifulSoup(pageText,'lxml')
            links = soup.select('h3.t a[href^="http://www.baidu.com/link?url="]')

            for l in links:
                noteInf = getNoteInfo(l.attrs['href'])
                seq += 1
                if noteInf is None:
                    #print(seq,'、',l.attrs['href'],None)
                    logPag(f"{seq}、{l.attrs['href']}:查找最新章节失败,忽略",True)
                else:
                    logPag(f"{seq}、返回小说信息: {noteInf}",True)
                    #chapter,cost,url,hostName,chaperUrl,chapterName = noteInf
                    validNoteInf.append(noteInf)
    validNoteInf.sort(key=noteWeight,reverse=True)
    print(f"小说: {inputword} 最新更新访问最快的5个网站是:")
    for l in validNoteInf[:5]:#输出相关搜索结果中具有最新章节且访问速度最快的前5个网站url
        print(f"{validNoteInf.index(l)+1}、第{l[0]}章 {l[-1]}  {getChapterUrl(l)}  ,网页打开耗时 {l[1]} 毫秒")
    input("按回车键退出!")

四、搜索案例

以搜索月关大大的青萍作为案例,执行搜索的语句为:

BDSearchUsingChrome('青萍月关',150)

执行结果:

小说: 青萍月关 最新更新访问最快的5个网站是:
1、第688章  东边日出西边雨  http://www.huaxiaci.com/41620/37631250.html  ,网页打开耗时 262.0 毫秒
2、第688章  东边日出西边雨  http://www.huaxiaci.com/41620/37631250.html  ,网页打开耗时 278.0 毫秒
3、第688章  东边日出西边雨  http://www.huaxiaci.com/41620/37631250.html  ,网页打开耗时 345.5 毫秒
4、第688章  东边日出西边雨  https://www.24kwx.com/book/9/9202/8889236.html  ,网页打开耗时 774.0 毫秒
5、第688章  东边日出西边雨  https://www.27kk.net/9526/2658932.html  ,网页打开耗时 800.5 毫秒
按回车键退出!

五、小结

本文介绍了使用Python搜索指定小说最新更新章节以及访问最快网站的实现思想和关键应用代码,实现自动搜索小说最新更新章节以及获取访问最快的网站。以上的实现由于已经获取最新章节的链接,再稍微改进,就可以直接将最新章节下载到本地观看。

到此这篇关于Python爬虫之爬取最新更新的小说网站的文章就介绍到这了,更多相关Python爬取最新更新的小说网站内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python 中的列表解析和生成表达式
Mar 10 Python
Python使用新浪微博API发送微博的例子
Apr 10 Python
详尽讲述用Python的Django框架测试驱动开发的教程
Apr 22 Python
详解python开发环境搭建
Dec 16 Python
Django中Forms的使用代码解析
Feb 10 Python
Python爬虫实例扒取2345天气预报
Mar 04 Python
Python对象转换为json的方法步骤
Apr 25 Python
python覆盖写入,追加写入的实例
Jun 26 Python
django项目登录中使用图片验证码的实现方法
Aug 15 Python
python django中8000端口被占用的解决
Dec 17 Python
matplotlib之pyplot模块坐标轴标签设置使用(xlabel()、ylabel())
Feb 22 Python
python基于tkinter实现gif录屏功能
May 19 Python
Python基础之操作MySQL数据库
Python 如何安装Selenium
Django实现在线无水印抖音视频下载(附源码及地址)
Django给表单添加honeypot验证增加安全性
Django利用AJAX技术实现博文实时搜索
May 06 #Python
python 如何获取页面所有a标签下href的值
May 06 #Python
Python中常见的导入方式总结
May 06 #Python
You might like
Yii 快速,安全,专业的PHP框架
2014/09/03 PHP
Zend Framework教程之前端控制器Zend_Controller_Front用法详解
2016/03/07 PHP
PHP读取mssql json数据中文乱码的解决办法
2016/04/11 PHP
PHP获取星期几的常用方法小结
2018/12/18 PHP
Laravel数据库读写分离配置的方法
2019/10/13 PHP
jquery validation插件表单验证的一个例子
2010/03/03 Javascript
jQuery 选择器、DOM操作、事件、动画
2010/11/25 Javascript
javascript确认框的三种使用方法
2013/12/17 Javascript
JS实现仿新浪微博发布内容为空时提示功能代码
2015/08/19 Javascript
jQuery插件实现无缝滚动特效
2015/11/24 Javascript
jquery.validate使用详解
2016/06/02 Javascript
javascript实现抽奖程序的简单实例
2016/06/07 Javascript
js改变html的原有内容实现方法
2016/10/05 Javascript
使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
2017/03/15 Javascript
JavaScript通过改变文字透明度实现的文字闪烁效果实例
2017/04/27 Javascript
js实现加载页面就自动触发超链接的示例
2017/08/31 Javascript
vue轮播图插件vue-concise-slider的使用
2018/03/13 Javascript
Node.js 使用AngularJS的方法示例
2018/05/11 Javascript
vue使用axios实现excel文件下载的功能
2020/07/16 Javascript
vue实现图书管理系统
2020/12/29 Vue.js
python使用urllib模块和pyquery实现阿里巴巴排名查询
2014/01/16 Python
Django卸载之后重新安装的方法
2017/03/15 Python
在Python中获取两数相除的商和余数方法
2018/11/10 Python
Python序列化pickle模块使用详解
2020/03/05 Python
详解python logging日志传输
2020/07/01 Python
用python实现前向分词最大匹配算法的示例代码
2020/08/06 Python
了解一下python内建模块collections
2020/09/07 Python
Omio波兰:全欧洲低价大巴、火车和航班搜索和比价
2018/02/16 全球购物
什么是Rollback Segment
2013/04/22 面试题
求职信模板怎么做
2014/01/26 职场文书
优秀家长自荐材料
2014/08/26 职场文书
合伙购房协议样本
2014/10/06 职场文书
2014年实习生工作总结
2014/11/27 职场文书
小学生暑假安全保证书
2015/07/13 职场文书
2015年秋季开学典礼校长致辞
2015/07/16 职场文书
python数据可视化使用pyfinance分析证券收益示例详解
2021/11/20 Python