审查元素与查看网页源代码不一致问题的解决(基于《三国演义》网络爬虫 含:with关键字,re库常用方法的解析)

本文介绍了如何使用Python的requests、re、beautifulsoup库和os库进行网络爬虫,包括抓取《三国演义》全文、解析目录和正文,以及提取特定内容。通过实际操作展示了爬虫的基本流程和技巧。
摘要由CSDN通过智能技术生成

一、实验目的

1. 掌握requests库、re库、beautifulsoup库、os库以及time库的使用。

2. 掌握正则表达式的基本操作。

3. 掌握网络爬虫的基本流程。

二、实验内容

本次实验分为以下两个任务。

2.1 任务一

从http://guoxue.lishichunqiu.com/gdxs/sanguoyanyi/网址中抓取《三国演义》名著全文。首先使用requests库完成目录页的抓取,然后使用正则表达式完成目录内容的解析,接下来使用beautifulsoup库获得每一回合的正文内容,再使用os库结合open函数将每回合的正文写进一个一个txt文件并保存在同一个文件夹里。

2.2 任务二

从抓取的“第二十一回·曹操煮酒论英雄 关公赚城斩车胄”文档中,使用正则表达式获取玄德与曹操的对话,并将这些对话写入一个txt文件。

三、实现方法

3.1 运行环境

PyCharm 2023.3.4   Python 3.10

3.2 基本操作

任务一的基本操作:

图1:任务一的基本操作

任务二的基本操作:

图2:任务二的基本操作

、实验结果

4.1 任务一

图3:shell打印出来的结果截图

图4:第二十回

图5:第二十一回

图6:二十二回

图7:存放每章正文内容的文件夹截图

4.2 任务二

图8:shell打印出来的结果截图

图9:玄德与曹操对话txt文件截图

、源程序清单

5.1 任务一

import requests
import re
from bs4 import BeautifulSoup
import os
import time

path = r"E:\Python_Study\Web_Spider_Data_Acquisition\Experiment03\三国演义"  # 要存储的文件夹

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0'
}
main_url = 'http://guoxue.lishichunqiu.com/gdxs/sanguoyanyi/'
page_text = requests.get(url=main_url, headers=headers)
page_text.encoding = 'UTF-8'
page = page_text.text  # 获取html代码
index_regex = '''<a style="font:14px/24px '宋体';" href="(.*?)" title=".*?">(.*?)</a>'''  # 定位目录,包括每一回的URL和每一回的题目
a_list = re.findall(index_regex, page)
print(a_list)
for i in a_list[19:22]:
    detail_url = i[0]  # detail_url=每一回的URL
    # 对详情页发起请求解析出章节内容
    page_detail = requests.get(url=detail_url, headers=headers)
    page_detail.encoding = 'UTF-8'
    page_detail = page_detail.text  # 获取该回合的html代码
    soup = BeautifulSoup(page_detail, 'html.parser')
    soup = soup.find_all('div', attrs={'id': "content"})  # 使用find_all方法,定位到'div'标签,属性为'id':"content",从而获得正文内容
    # soup.find_all(标签,attrs={属性})
    content = ''
    for con in soup:
        c = con.text
        content += c
    # 数据持久化,存储小说
    if not os.path.exists(path):
        os.mkdir(path)
    with open(path + './%s' % i[1] + '.txt', 'w', encoding='utf-8') as file:
        file.write(content + '\n')
        print("正在下载:" + i[1])
        time.sleep(2)

5.2 任务二 

import re

f = open(
    r"E:\Python_Study\Web_Spider_Data_Acquisition\Experiment03\三国演义\第二十一回·曹操煮酒论英雄 关公赚城斩车胄.txt",
    "r", encoding="utf-8")
txt = f.read()
f.close()
pt = "(玄德.{0,2}曰:“.{1,40}”操.{0,10}曰:“[^”]{1,100}”)"
count = 0
with open(r'E:\Python_Study\Web_Spider_Data_Acquisition\Experiment03\三国演义\曹操煮酒论英雄对话.txt', 'w',
          encoding='utf-8') as f:
    for i in re.finditer(pt, txt):
        f.write(i.group() + '\n')
        count += 1
print(f"玄德与曹操对话共{count}条")

、思考及总结

6.1with语句:(python中的关键字)

一个上下文管理器:在代码块执行前准备,代码块执行后收拾

相当于是创建了一个环境,处理上下文环境产生的异常

最关键的作用:代码块执行完毕后自动执行清理操作,无论代码块是否成功执行

1:最简单,经典的例子就是文件操作:

f = open("File_Path")

data = f.read()

"""

data的一系列操作

"""

f.close()

这样的代码:

1.过于冗长,不够优雅

2. 忘记关闭文件,导致文件一直被占用着

3.读取文件时出现异常,代码无法进行

改为如下代码:

with open("File_Path") as f:

    data = f.read()

    """

    data的一系列操作

    """

2: with的底层

相当于封装了两个魔术方法(在执行with语句时会自动执行)__enter__()和__exit__()

(是以双下划线(__)开头和结尾的特殊方法,这些方法在对象的创建、操作和销毁等过程中被自动调用,从而实现对对象的控制和定制)

3.with的三个步骤:

step1. 执行with语句前:__enter__()方法先被执行

step 2. 执行with语句中:执行with中的代码块

step 3. 执行with语句后(with代码被执行完毕):

    __exit__()方法被调用

    即使出现错误,也会调用 __exit__() 方法,关闭文件流

4.with在python中其他用法

多线程:acquire()->代码块->release()

Python Threading中的Lock模块有acquire()和release()两种方法

数据库连接:__enter__()->代码块->__exit__()

import sqlite3

with sqlite3.connect('database.db') as conn:

    cursor = conn.cursor()

    cursor.execute("SELECT * FROM table_name")

    rows = cursor.fetchall()

# 在 with 代码块结束后,数据库连接会自动关闭

网络请求:__enter__()->代码块->__exit__()

import requests



with requests.get('url') as response:

    print(response.text)

# 在 with 代码块结束后,网络连接会自动关闭

6.2:复制的元素与直接打印出来的html不一致的问题

在使用检查,copy element的时候出现了一个很严重的问题,即复制的元素与直接打印出来的html不一致的问题,具体情况如下:

在Edge和谷歌浏览器中,出现以下问题:

图9:控制台打印出来的html代码

图10:谷歌浏览器检查元素

图11:Edge检查元素

网页源代码展示,Python 爬虫获取源代码和Element不一样的页面.

为什么会多这么一个属性值呢?

如果是这样的话,爬虫就不能只查看元素了,这是一个很棘手的问题啊!

这里,我们不对进行元素的查看,直接查看源代码,我们有一个发现:

图12:Edge源代码(这样的结果就是正确的)

可直观看到"査看网页源代码”的代码内容是服务器发送到浏览器的原封不动的源代码,不包括页面动态渲染的内容;“审查元素”包括源代码+js动态渲染的内容,即最终展示的html内容(前端的一些知识)。

图13:Edge查找数据的一般操作

这样就初步解决了上述html '不同'的问题

那么更进一步:

为什么其他属性的都有,偏偏只有这一个属性值没有呢?这里涉及到前端的知识:data-*诸如此类的属性值是供JavaScript 或 CSS 使用.我们所看到的html代码是浏览器自动优化过的,我们爬虫的时候的html也是经过处理过的,只有裸露的html代码

仍然是该网站:

图14:Edge检查元素

图15:Edge查看网页源代码

这就证明了我们爬虫的时候的html也是经过处理过的,去处理JavaScript 或 CSS的渲染(如data-*诸如此类的属性值),所以,当我们对网页进行爬虫的时候,应该检查网页的源代码(或者去谷歌留来其中检查元素),这样可以有效避免我们对html解析的时候,出现的html '不同'的问题.

6.3: re.finditer()方法源代码解析:

图16:finditer源代码

这段代码的含义是使用re.compile()函数编译正则表达式pattern并设置标志flags,然后调用编译后的正则表达式对象的finditer()方法在字符串string中查找所有匹配项。最后仍然调用了_compile()方法.

图17: _compile()源代码

(在 Python 中,将方法名字前面加一个单下划线(_)是一种约定俗成的方式,它表示这个方法是“私有”的,不应该被其他模块或代码直接调用。)

_compile(pattern,flags) 其实就是使用该正则表达式模板,去不断对string匹配,用于生成一个可迭代对象.这样做的好处是可以提高性能,因为编译后的正则表达式对象可以被重复使用,避免了每次都重新编译正则表达式。

6.4:心得体会

爬虫无外乎就是这几步,有难度的就只有解析数据这一步,只要我们能够熟练的掌握基本解析库中的方法,方法三要素(方法名,参数,返回值),并对可能产生的异常结果进行一个处理等,更好,更健壮的爬虫程序都能被做出来(暂时不考虑反爬的情况)

图18: 爬虫一般步骤

  • 24
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值