(Python爬虫)番茄小说-《超级上门女婿》

引言

        网络爬虫,作为一种自动化获取网络信息的工具,就在这个探索中扮演着至关重要的角色。通过模拟人类浏览行为,它们能够在互联网的广阔海洋中捕捉到我们所需要的信息片段。但有时,直接获取的信息并不总是以我们期待的形式呈现。例如,在某些情况下,为了保护内容,网站可能会对数据进行编码或加密。这就需要我们不仅要有抓取数据的能力,更要有解码这些数据的智慧。

        我们将从最基础的库引入开始,逐步深入到如何发送网络请求、解析HTML文档、识别并转换乱码编码,最终实现清晰文本的提取。

一、数据来源分析

目标对象

        以爬取番茄小说网站中的文本为例。这里的目标对象分为:网址、小说标题、章节标题、内容、作者。

首先是爬虫目标对象,网址:超级上门女婿完整版在线免费阅读_超级上门女婿小说_番茄小说官网番茄小说提供超级上门女婿完整版在线免费阅读,精彩小说尽在番茄小说网。窝囊废物的上门女婿叶凡,无意中得到太极经和生死石的传承,自此开始了不一样的人生,他医术救美,武道杀敌...icon-default.png?t=N7T8https://fanqienovel.com/page/6751820766397860871

其次是明确抓包内容,我们这次爬虫需要获取的还有标题、章节标题、内容以及作者的数据。

我们要知道他们在HTML中对应的标签位置。

        1)分析数据位置

        a)进入目标对象网址,打开开发者工具(F12键/右键选择检查)

        b)在开发者工具中选择(网络/network)并刷新目标对象网页,重新录制网络活动观察网络请求状态

        c)通过开发者工具左上角小箭头选取网页对应的元素,了解对应标签位置,如下图:

 图一 开发者工具选取HTML网页对应的元素

        主标题获取方式已知晓,作者也在旁边也可以采用同样的方法。在这里细说标题跟内容爬取,我们要知道小说标题、内容在哪?我们通过浏览器手段去看小说怎么进入?怎么看到的?

 图二 小说章节目录处

        一般来说我们在看小说都是在目录点击观看的,但我们可以发现,目录下的每一章小说标题网页结构是相同的,如下图所示。

 图三 小说章节目录标签结构

        我们是通过其中的超链接进入的每个章节内容页面中的,点进其中一个超链接,进入到内容区

图四 小说内容区域的网络活动状态

        通过网络状态中我们找到对应的返回过来的小说内容(如果找不到可以复制小说中的其中一段内容在网络状态中搜索)

        2)分析不同章节的变化规律

        第一章url:https://fanqienovel.com/reader/6751837026556838404

        第二章url:https://fanqienovel.com/reader/6751837026573615627

        可以看出小说两个章节之间的区别是reader/后面的id不同,通过不同的id跳转到不同的章节目录中去,即获取小说所有的id即可访问所有的章节内容

        3)分析不同id可以从哪里获取

        关于id的变化,在图二中有所提到,在该小说页面的主界面的目录下,存在着该小说的全部章节的跳转路由,在图三中我们也可以看到每个章节对应一个a标签。

<a href="/reader/6751837026556838404" class="chapter-item-title" target="_blank">第一章 受尽白眼</a>

        像这样的a标签有很多,所以我们只需要获取当前小说主页的目录下的这些a标签中的href链接即可。

二、代码实现

爬虫的四个基本步骤

1.发送请求:爬虫需要与目标网站建立通信。我们通常会使用requests这样的库来模拟浏览器发送HTTP请求。请求可以是简单的GET请求,用来索取数据;也可以是POST请求,提交表单信息等。为了使请求看起来更像是由真实用户发起,而非自动化脚本,爬虫往往需要设置请求头(Headers),包括用户代理(User-Agent)、认证令牌(Tokens)、Cookies等,来绕过网站的安全措施如CAPTCHA、限速等。

2.获取数据:一旦请求被发出并由服务器响应,爬虫会接收到包含目标信息的数据。这些数据通常是HTML格式,但也可能是JSON、XML或其他类型的数据。此时的数据是原始的,可能包括大量的结构化和非结构化信息,需要进一步的处理才能变得有用。

3.解析数据:获得数据后,爬虫需要处理并提取有用的信息。解析数据通常涉及HTML解析器如parsel,它能够解析HTML文档,提取出需要的元素、属性等。通过CSS选择器或XPath表达式,可以精确地定位页面中的特定部分,用于提取文本、链接、图片地址等。某些情况下,还需要对数据进行解码或格式转换,以确保提取出的信息是准确和可读的。

4.保存数据:在提取并清洗好数据之后,最后一步便是将其保存起来,以便未来的使用和分析。数据可以以不同的格式保存,如写入文本文件、CSV、JSON,或存储到数据库中。选择最佳的存储方式通常取决于数据的类型和预期用途。例如,对于结构化数据,数据库是一个很好的选择;而对于单一数据类型或文本数据,文本文件或CSV文件可能更加方便。存储过程中还可能涉及到数据的进一步处理,例如数据去重、转换编码、数据清洗等,以确保保存的数据是高质量和一致的。

第一次请求:获取章节ID,小说名,章节名

发送请求:请求小说目录页:https://fanqienovel.com/page/6751820766397860871

获取数据:获取网页源代码

解析数据:提取章节的ID/章节名

第二次请求:获取内容

发送请求:请求连接章节链接

        第一次请求获取到的章节ID(前面提到的链接:/reader/6751837026556838404)

        将章节id拼接在前面固定的url后

获取数据:获取网页的源代码

解析数据:提取章节内容

保存数据:保存爬取出的小说内容

具体代码实现

******请注意******

headers = {

'Cookie': ‘’,        #需要自己在浏览器中提供

'User-Agent': ''    #需要自己在浏览器中提供

}

获取方式:在开发者工具中的网络下找到对应的网络状态,在标头处找到Cookie和User-Agent将他们复制在对应的''中,如下图所示

图五 获取Cookie和User-Agent 

# 1. 导入必需的库
import requests  # 发起网络请求
import parsel  # 解析HTML

# 2. 番茄小说中的乱码字典,用于解码网页中的特定编码字符
dict_data = {
    '58670': '0',
    '58413': '1',
    '58678': '2',
    '58371': '3',
    '58353': '4',
    '58480': '5',
    '58359': '6',
    '58449': '7',
    '58540': '8',
    '58692': '9',
    '58712': 'a',
    '58542': 'b',
    '58575': 'c',
    '58626': 'd',
    '58691': 'e',
    '58561': 'f',
    '58362': 'g',
    '58619': 'h',
    '58430': 'i',
    '58531': 'j',
    '58588': 'k',
    '58440': 'l',
    '58681': 'm',
    '58631': 'n',
    '58376': 'o',
    '58429': 'p',
    '58555': 'q',
    '58498': 'r',
    '58518': 's',
    '58453': 't',
    '58397': 'u',
    '58356': 'v',
    '58435': 'w',
    '58514': 'x',
    '58482': 'y',
    '58529': 'z',
    '58515': 'A',
    '58688': 'B',
    '58709': 'C',
    '58344': 'D',
    '58656': 'E',
    '58381': 'F',
    '58576': 'G',
    '58516': 'H',
    '58463': 'I',
    '58649': 'J',
    '58571': 'K',
    '58558': 'L',
    '58433': 'M',
    '58517': 'N',
    '58387': 'O',
    '58687': 'P',
    '58537': 'Q',
    '58541': 'R',
    '58458': 'S',
    '58390': 'T',
    '58466': 'U',
    '58386': 'V',
    '58697': 'W',
    '58519': 'X',
    '58511': 'Y',
    '58634': 'Z',
    '58611': '的',
    '58590': '一',
    '58398': '是',
    '58422': '了',
    '58657': '我',
    '58666': '不',
    '58562': '人',
    '58345': '在',
    '58510': '他',
    '58496': '有',
    '58654': '这',
    '58441': '个',
    '58493': '上',
    '58714': '们',
    '58618': '来',
    '58528': '到',
    '58620': '时',
    '58403': '大',
    '58461': '地',
    '58481': '为',
    '58700': '子',
    '58708': '中',
    '58503': '你',
    '58442': '说',
    '58639': '生',
    '58506': '国',
    '58663': '年',
    '58436': '着',
    '58563': '就',
    '58391': '那',
    '58357': '和',
    '58354': '要',
    '58695': '她',
    '58372': '出',
    '58696': '也',
    '58551': '得',
    '58445': '里',
    '58408': '后',
    '58599': '自',
    '58424': '以',
    '58394': '会',
    '58348': '家',
    '58426': '可',
    '58673': '下',
    '58417': '而',
    '58556': '过',
    '58603': '天',
    '58565': '去',
    '58604': '能',
    '58522': '对',
    '58632': '小',
    '58622': '多',
    '58350': '然',
    '58605': '于',
    '58617': '心',
    '58401': '学',
    '58637': '么',
    '58684': '之',
    '58382': '都',
    '58464': '好',
    '58487': '看',
    '58693': '起',
    '58608': '发',
    '58392': '当',
    '58474': '没',
    '58601': '成',
    '58355': '只',
    '58573': '如',
    '58499': '事',
    '58469': '把',
    '58361': '还',
    '58698': '用',
    '58489': '第',
    '58711': '样',
    '58457': '道',
    '58635': '想',
    '58492': '作',
    '58647': '种',
    '58623': '开',
    '58521': '美',
    '58609': '总',
    '58530': '从',
    '58665': '无',
    '58652': '情',
    '58676': '己',
    '58456': '面',
    '58581': '最',
    '58509': '女',
    '58488': '但',
    '58363': '现',
    '58685': '前',
    '58396': '些',
    '58523': '所',
    '58471': '同',
    '58485': '日',
    '58613': '手',
    '58533': '又',
    '58589': '行',
    '58527': '意',
    '58593': '动',
    '58699': '方',
    '58707': '期',
    '58414': '它',
    '58596': '头',
    '58570': '经',
    '58660': '长',
    '58364': '儿',
    '58526': '回',
    '58501': '位',
    '58638': '分',
    '58404': '爱',
    '58677': '老',
    '58535': '因',
    '58629': '很',
    '58577': '给',
    '58606': '名',
    '58497': '法',
    '58662': '间',
    '58479': '斯',
    '58532': '知',
    '58380': '世',
    '58385': '什',
    '58405': '两',
    '58644': '次',
    '58578': '使',
    '58505': '身',
    '58564': '者',
    '58412': '被',
    '58686': '高',
    '58624': '已',
    '58667': '亲',
    '58607': '其',
    '58616': '进',
    '58368': '此',
    '58427': '话',
    '58423': '常',
    '58633': '与',
    '58525': '活',
    '58543': '正',
    '58418': '感',
    '58597': '见',
    '58683': '明',
    '58507': '问',
    '58621': '力',
    '58703': '理',
    '58438': '尔',
    '58536': '点',
    '58384': '文',
    '58484': '几',
    '58539': '定',
    '58554': '本',
    '58421': '公',
    '58347': '特',
    '58569': '做',
    '58710': '外',
    '58574': '孩',
    '58375': '相',
    '58645': '西',
    '58592': '果',
    '58572': '走',
    '58388': '将',
    '58370': '月',
    '58399': '十',
    '58651': '实',
    '58546': '向',
    '58504': '声',
    '58419': '车',
    '58407': '全',
    '58672': '信',
    '58675': '重',
    '58538': '三',
    '58465': '机',
    '58374': '工',
    '58579': '物',
    '58402': '气',
    '58702': '每',
    '58553': '并',
    '58360': '别',
    '58389': '真',
    '58560': '打',
    '58690': '太',
    '58473': '新',
    '58512': '比',
    '58653': '才',
    '58704': '便',
    '58545': '夫',
    '58641': '再',
    '58475': '书',
    '58583': '部',
    '58472': '水',
    '58478': '像',
    '58664': '眼',
    '58586': '等',
    '58568': '体',
    '58674': '却',
    '58490': '加',
    '58476': '电',
    '58346': '主',
    '58630': '界',
    '58595': '门',
    '58502': '利',
    '58713': '海',
    '58587': '受',
    '58548': '听',
    '58351': '表',
    '58547': '德',
    '58443': '少',
    '58460': '克',
    '58636': '代',
    '58585': '员',
    '58625': '许',
    '58694': '稜',
    '58428': '先',
    '58640': '口',
    '58628': '由',
    '58612': '死',
    '58446': '安',
    '58468': '写',
    '58410': '性',
    '58508': '马',
    '58594': '光',
    '58483': '白',
    '58544': '或',
    '58495': '住',
    '58450': '难',
    '58643': '望',
    '58486': '教',
    '58406': '命',
    '58447': '花',
    '58669': '结',
    '58415': '乐',
    '58444': '色',
    '58549': '更',
    '58494': '拉',
    '58409': '东',
    '58658': '神',
    '58557': '记',
    '58602': '处',
    '58559': '让',
    '58610': '母',
    '58513': '父',
    '58500': '应',
    '58378': '直',
    '58680': '字',
    '58352': '场',
    '58383': '平',
    '58454': '报',
    '58671': '友',
    '58668': '关',
    '58452': '放',
    '58627': '至',
    '58400': '张',
    '58455': '认',
    '58416': '接',
    '58552': '告',
    '58614': '入',
    '58582': '笑',
    '58534': '内',
    '58701': '英',
    '58349': '军',
    '58491': '候',
    '58467': '民',
    '58365': '岁',
    '58598': '往',
    '58425': '何',
    '58462': '度',
    '58420': '山',
    '58661': '觉',
    '58615': '路',
    '58648': '带',
    '58470': '万',
    '58377': '男',
    '58520': '边',
    '58646': '风',
    '58600': '解',
    '58431': '叫',
    '58715': '任',
    '58524': '金',
    '58439': '快',
    '58566': '原',
    '58477': '吃',
    '58642': '妈',
    '58437': '变',
    '58411': '通',
    '58451': '师',
    '58395': '立',
    '58369': '象',
    '58706': '数',
    '58705': '四',
    '58379': '失',
    '58567': '满',
    '58373': '战',
    '58448': '远',
    '58659': '格',
    '58434': '士',
    '58679': '音',
    '58432': '轻',
    '58689': '目',
    '58591': '条',
    '58682': '呢'
}
# 3. 模拟浏览器的请求头,伪装成浏览器用户,避免被网站拦截
headers = {
    'Cookie': '',  #根据实际情况需要自己在浏览器中提供
    'User-Agent': ''  #根据实际情况需要自己在浏览器中提供
}  
# 4. 发送请求,获取网页内容
url = 'https://fanqienovel.com/page/6751820766397860871'
response = requests.get(url=url, headers=headers)
html = response.text

# 5. 使用parsel提取小说名称、章节标题和链接
selector = parsel.Selector(html)
name = selector.css('.info-name h1::text').get()  # 提取小说名称
title_list = selector.css('.chapter-item-title::text').getall()  # 提取章节标题列表
href = selector.css('.chapter-item-title::attr(href)').getall()  # 提取链接后缀列表

# 6. 调整章节链接列表,移除列表中的第一个元素,因为它不是目标章节的一部分
href.pop(0)
# print(href)
# 7. 循环提取每个章节的内容
for title, link in zip(title_list, href):
    link_url = 'https://fanqienovel.com' + link  # 构造完整的章节URL
    link_data = requests.get(url=link_url, headers=headers).text  # 请求章节URL并获取内容
    link_selector = parsel.Selector(link_data)
    content_list = link_selector.css('.muye-reader-content-16 p::text').getall()  # 提取章节文本内容

    # 解码章节文本,将乱码字符映射为实际字符
    novel_content = ''
    for paragraph in content_list:
        # 解码段落并添加到novel_content
        for index in paragraph:
            try:
                word = dict_data[str(ord(index))]  # 尝试根据字符的Unicode码点在字典中查找映射
            except KeyError:
                word = index  # 如果查找失败,使用原始字符
            novel_content += word  # 将解码后的字符追加到章节内容中
        novel_content += '\n'  # 每个段落后添加两个换行符

    print(title)  # 打印章节标题
    print(link_url)  # 打印章节url
    # print(novel_content)  # 打印解码后的章节内容
    # 写入文件,并保存爬取内容
    with open(name + '.txt', mode='a', encoding='utf-8') as f:
        f.write(title)
        f.write('\n')
        f.write(novel_content)
        f.write('\n')

代码及注释附上。

字典数据参考博客:https://www.cnblogs.com/ruichow/p/18209338

学习视频参考:Python解决【字体加密】采集番茄小说数据_哔哩哔哩_bilibili

爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值