SpiderBuf--爬虫练习网站手把手带练(最新独特版1-10) - 实践

网站:Python 爬虫实战练习案例 - Python 爬虫练习网站

这是一个爬虫练习网站  适合练习 查漏补缺

第一题:

Ctrl+U 查看页面源代码 然后 Ctrl+F 打开搜索框 搜索我们想要的内容

可以看到我们爬取的数据都在其中  至此 确定该网站为静态数据

接着我们F12 打开开发者工具 此时不需要Ctrl+R 刷新页面  因为我们获取的是静态数据
点击元素  左上角小箭头 选中我们想好爬取的数据 分析页面结构

分析网页结构

OK 此时我们如果直接定位到tbody的话 此页面有五个 不好定位 我们按照层级定位

定位: class属性为table的table标签下面的tbody 里面的tr 此时刚好为十条返回结构 符合我们爬取数据的条数

OK 页面的层级分析定位完毕 现在我们开始写代码

The first step is to build headers

点击网络(network)  一次性将所有的请求头复制下来 一锅端

这里推荐一个插件 可以提高我们构建请求头的效率  在插件商城里面搜 headers 出来一个蜘蛛的图标 下载即可

使用方法: 复制请求头信息后  到Pycharm 里面右击复制 里面有个选项 Headers 复制为headers

目前代码如下   编写代码
# 导包
import requests
url = 'https://spiderbuf.cn/web-scraping-practice/requests-lxml-for-scraping-beginner'
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "cookie": "_ga=GA1.1.708657061.1763371540; __gads=ID=98ca5ab3854f8f7b:T=1763371542:RT=1764764086:S=ALNI_MarOlLEhFCBjKmYlgNY0raV9R7gNg; __gpi=UID=000011b788c64afc:T=1763371542:RT=1764764086:S=ALNI_Mbts5XM02bKGB6uNwuvlFoz8CPhqw; __eoi=ID=cd119b00af58d9e4:T=1763371542:RT=1764764086:S=AA-AfjbIBrUY97XhQd5DGDYSZ-on; _ga_7B42BKG1QE=GS2.1.s1764763461$o3$g1$t1764764086$j55$l0$h0",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practices/1?order=learn",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
resp = requests.get(url, headers=headers)
print(resp.text)

在终端查看返回的源代码

发现返回的是一串乱码 哦豁
这里有一个乱码的样式 总结 大家可以查看一下

第一反应就是 第二个 是吧 但是我们以UTF-8的方式 读取 依然没用
resp.encoding = 'utf-8'

解决方法 就是删掉请求头中的 accept-encoding 这个参数是指定客户端接受的压缩编码格值"gzip, deflate, br, zstd"表示客户端支持四种压缩算法:gzip、deflate、br(Brotli)和zstd,服务器可以根据这些选项选择合适的压缩方式来减少传输数据量。

直接删掉其它的留下gzip即可 或者把这行都删了 or 注释掉 默认为gzip压缩格式
有时候页面出现类似的代码 有可能是受br的影响 删掉即可

此时运行 即可看到页面的源代码 我们想要的数据也在其中

继续写代码  解析数据 导入用到的包

from lxml import etree

html = etree.HTML(resp.text)
lis = html.xpath('.//table[@class="table"]/tbody/tr')
lis = html.xpath('.//table[@class="table"]/tbody/tr')
# 遍历根节点
for li in lis:
    number = ''.join(li.xpath('./td[1]/text()'))
    ip_address = ''.join(li.xpath('./td[2]/text()'))
    Mac_address = ''.join(li.xpath('./td[3]/text()'))
    device_name = ''.join(li.xpath('./td[4]/text()'))
    device_type = ''.join(li.xpath('./td[5]/text()'))
    operating_system = ''.join(li.xpath('./td[6]/text()'))
    opening_port = ''.join(li.xpath('./td[last()-1]/text()'))
    if not opening_port:
        opening_port = '无'
    online = ''.join(li.xpath('./td[last()]/text()'))

Explain:
        正则提取出来的数据返回的是一个列表 此时我们想到可以将其取出来[0]
        但是这样其实不好  假如要取的那个字段是空的 就会报错 索引超过列表长度
        因为里面是空的 你还要进行取值 正确的处理方式是将其转化成字符串

opening_port字段 我们通过网页可以发现是空的
如果不处理 那么得到的也是空数据 当然我们也可以进行处理
not 取反 意思是 如果这个字段为空 则返回 空字符串

至此 我们爬取的所有数据就搞定了  将所有的字段打印出来 检查符合格式要求 就可以进行数据的保存了

保存数据为csv 文件
# 创建一个名为'S_b_1.csv'的文件,以写入模式('w')打开,使用UTF-8-SIG编码格式,并设置newline=''来避免CSV文件中出现额外的空行
f = open('S_b_1.csv', 'w', encoding='utf-8-sig', newline='')
# 写入表头
f.write('number,ip_address,Mac_address,device_name,device_type,operating_system,opening_port,online\n')
# 使用格式化字符串 将我们的数据一行对应表头写入 以逗号隔开 csv文件的格式
all_data = f'{number},{ip_address},{Mac_address},{device_name},{device_type},{operating_system},{opening_port},{online}\n'
    f.write(all_data)
# 关闭文件
f.close()

编码格式为utf-8-sig 可以在excel里面打开 而不出现乱码
运行看到我们的数据 会发现开放端口那个字段 本身就有, 所以保存的数据有问题
我们可以将里面所有的英文逗号改成中文的 即可正常保存

# 如果字符串中存在英文逗号 就执行替换
if ',' in opening_port:
    opening_port = opening_port.replace(',',',')

以下是保存成功的数据 以及所有的代码 供大家参考学习

import requests
from lxml import etree
url = 'https://spiderbuf.cn/web-scraping-practice/requests-lxml-for-scraping-beginner'
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    # "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "cookie": "你的cookie",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practices/1?order=learn",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
resp = requests.get(url, headers=headers)
f = open('S_b_1.csv', 'w', encoding='utf-8-sig', newline='')
html = etree.HTML(resp.text)
lis = html.xpath('.//table[@class="table"]/tbody/tr')
f.write('number,ip_address,Mac_address,device_name,device_type,operating_system,opening_port,online\n')
for li in lis:
    number = ''.join(li.xpath('./td[1]/text()'))
    ip_address = ''.join(li.xpath('./td[2]/text()'))
    Mac_address = ''.join(li.xpath('./td[3]/text()'))
    device_name = ''.join(li.xpath('./td[4]/text()'))
    device_type = ''.join(li.xpath('./td[5]/text()'))
    operating_system = ''.join(li.xpath('./td[6]/text()'))
    opening_port = ''.join(li.xpath('./td[7]/text()'))
    if ',' in opening_port:
        opening_port = opening_port.replace(',',',')
    if not opening_port:
        opening_port = '无'
    online = ''.join(li.xpath('./td[last()]/text()'))
    all_data = f'{number},{ip_address},{Mac_address},{device_name},{device_type},{operating_system},{opening_port},{online}\n'
    f.write(all_data)
f.close()

第二题:

这个考察点 我们在第一个题目的时候已经完成了 只需要把请求头构造完整即可

将请求地址修改即可

第三题: 

前面基本的步骤我就不重复了  

分析页面  页面的结构相比之前 有点改动 需要我们稍微调整一下代码  已经Url

主要修改这两个:

  • 第二个td 标签 下面的a标签 提取其中的文本
  • 最后一个td标签 下面的font标签 提取其中的文本
ip_address = ''.join(li.xpath('./td[2]/a/text()'))
online = ''.join(li.xpath('./td[last()]/font/text()'))

第四题:

依然F12打开开发者工具 分析页面的结构

发现和之前第二题的页面结构一样  直接把之前的代码拿过来运行 可得

确认代码没有问题 可以拿到数据 接下来爬取五页的所有数据

点击页码 查看页码之间的关联

可以看到 Url地址中拼接了页码的参数 pageno=2

我们可以循环遍历 将每一页的数据保存下来  如果是将所有的数据保存到一个文件中 还需要调整一下代码的顺序

就是和文件打开 关闭 以及写入表头的代码

Explain:  因为我们保存到一个文件中就只需 打开一次 待所有的数据都写入后再关闭 表头都是一样的 所以就只要写入一次

还有一个小细节 就是number 序列 第一个字段 都是从0开始 我们可以在循环外面定义一个字段每循环一次加1

第四题的代码如下

import requests
from lxml import etree
f = open('S_b_4.csv', 'w', encoding='utf-8-sig', newline='')
f.write('number,ip_address,Mac_address,device_name,device_type,operating_system,opening_port,online\n')
count = 1
# range 函数 只写一个数字 默认代表的是从0开始 到数字-1结束 左闭右开
# 从1开始 到5 结束
for page in range(1, 6):
    url = f'https://spiderbuf.cn/web-scraping-practice/web-pagination-scraper?pageno={page}'
    headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        # "accept-encoding": "gzip, deflate, br, zstd",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "cache-control": "no-cache",
        "cookie": "你的cookie",
        "pragma": "no-cache",
        "priority": "u=0, i",
        "referer": "https://spiderbuf.cn/web-scraping-practices/1?order=learn",
        "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\"",
        "sec-fetch-dest": "document",
        "sec-fetch-mode": "navigate",
        "sec-fetch-site": "same-origin",
        "sec-fetch-user": "?1",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
    }
    resp = requests.get(url, headers=headers)
    html = etree.HTML(resp.text)
    lis = html.xpath('.//table[@class="table"]/tbody/tr')
    for li in lis:
        # number = ''.join(li.xpath('./td[1]/text()'))
        number = count
        ip_address = ''.join(li.xpath('./td[2]/text()'))
        Mac_address = ''.join(li.xpath('./td[3]/text()'))
        device_name = ''.join(li.xpath('./td[4]/text()'))
        device_type = ''.join(li.xpath('./td[5]/text()'))
        operating_system = ''.join(li.xpath('./td[6]/text()'))
        opening_port = ''.join(li.xpath('./td[7]/text()'))
        if ',' in opening_port:
            opening_port = opening_port.replace(',', ',')
        if not opening_port:
            opening_port = '无'
        online = ''.join(li.xpath('./td[last()]/text()'))
        all_data = f'{number},{ip_address},{Mac_address},{device_name},{device_type},{operating_system},{opening_port},{online}\n'
        f.write(all_data)
        count+=1
f.close()

这样的话就比较美观

刚刚说了 如果你是想每一页保存为一个文件的话 就得做如下的调整 思路换一下

这样就不需要调写入文件相关的代码 只需将保存的文件名换成变量即可

这样就完成了分页保存


第五题:

第五题就不一样了 是需要我们爬取几张图片 

思路:  拿到所有的图片链接 对链接发请求 拿到二进制数据 进而进行保存

Explain:
当爬取的文件包含非文本数据(如图片、音视频、压缩包、可执行文件等)时,必须使用二进制模式保存

  • 图片是由像素点组成的,每个像素有RGB值等二进制数据

  • 如果以文本模式保存,编码转换会破坏文件结构,导致图片损坏

OK 我们来分析页面的结构

可以发现 所有的图片都在 class 类名为tabel-responsive的div标签中
根标签可以选则从这里开始 也可以直接通过img中的class属性来定位 

OK 开始写代码

# 导包
import requests
from lxml import etree
url = 'https://spiderbuf.cn/web-scraping-practice/scraping-images-from-web'
# 构建请求头
headers = {
    "content-type": "text/plain;charset=UTF-8",
    "referer": "https://spiderbuf.cn/",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
resp = requests.get(url, headers=headers)
html = etree.HTML(resp.text)
images = html.xpath('.//img[@class="img-responsive img-thumbnail"]/@src')
print(images)

打印出来 发现这个地址是不完整的

这个是完整的链接地址  我们需要做个拼接

# 返回的是个列表
# 遍历列表 拿到具体的值
for img in images:
    # 拼接 打印
    img_url = 'https://spiderbuf.cn'+ img
    print(img_url)

在终端点击链接可以看到图片 说明拼接没有问题

现在的需求是:  将所有的图片保存到当前的新的文件夹中 命名为1-5.jpg 

实现代码:
if not os.path.exists('img_S_b'):
    os.makedirs('img_S_b')
for idx, img in enumerate(images):
    img_url = 'https://spiderbuf.cn' + img
    resp_img = requests.get(img_url, headers=headers).content
    with open(f'./img_S_b/{idx + 1}.png', 'wb') as f:
        f.write(resp_img)

Explain:
        检查当前目录下是否存在名为'img_S_b'的文件夹,如果不存在,则创建该文件夹。
        具体逻辑:
                        1. `os.path.exists('img_S_b')` - 检查'img_S_b'路径是否存在
                        2. `not` - 对检查结果取反
                        3. `os.makedirs('img_S_b')` - 创建'img_S_b'目录及其父目录(如需要)

enumerate 就是相比较于没有 多了个idx 列表的索引值 方便后续保存图片

使用`enumerate()`函数遍历列表,同时获取每个元素的索引(idx)和对应的图像数据(img)。enumerate()会自动为列表中的每个元素生成从0开始的索引,便于在循环中同时访问索引位置和实际数据。

with open 和open 的区别 open 需要手动关闭文件 f.close()

以wb 二进制的形式写入文件

至此 所有的图片爬取完毕



第六题:

前面基本的步骤就不讲了  分析此页面 发现和第三题的页面结构一样 我们把之前写的代码拿过来 修改url地址试一下

运行之后发现没有内容

回到页面当中分析原因----  可以看到我们整个html页面都在这个iframe标签中

当数据在 iframe 中时  需要 先获取 iframe 的 src 地址 然后 单独请求 iframe 中的内容

相当于本网页中嵌入了别的网站的链接 需要到本来的网站的爬取数据

OK 开始写代码 这次我们写函数 有重复的代码

import requests
from lxml import etree
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    # "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "cookie": "你的cookie",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practices/1?order=learn",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
def get_inner_url(url):
    resp = requests.get(url, headers=headers)
    html = etree.HTML(resp.text)
    ini_url = 'https://spiderbuf.cn' + ''.join(html.xpath('.//iframe/@src'))
    return ini_url, html

定义一个函数 形参将提取到的链接拼接好之后 和转换的html返回 方便后续发请求
之后再定义一个主函数 

def main():
    inner_url, html = get_inner_url('https://spiderbuf.cn/web-scraping-practice/scraping-iframe')
    # 对实际的地址发起请求
    inner_urls, htmls = get_inner_url(inner_url)
    # 以下和之前的题目一样 就不解释了
    lis = htmls.xpath('.//table[@class="table"]/tbody/tr')
    f = open('S_b_6.csv', 'w', encoding='utf-8-sig', newline='')
    f.write('number,ip_address,Mac_address,device_name,device_type,operating_system,opening_port,online\n')
    for li in lis:
        number = ''.join(li.xpath('./td[1]/text()'))
        ip_address = ''.join(li.xpath('./td[2]/a/text()'))
        Mac_address = ''.join(li.xpath('./td[3]/text()'))
        device_name = ''.join(li.xpath('./td[4]/text()'))
        device_type = ''.join(li.xpath('./td[5]/text()'))
        operating_system = ''.join(li.xpath('./td[6]/text()'))
        opening_port = ''.join(li.xpath('./td[7]/text()'))
        if ',' in opening_port:
            opening_port = opening_port.replace(',', ',')
        if not opening_port:
            opening_port = '无'
        online = ''.join(li.xpath('./td[last()]/font/text()'))
        all_data = f'{number},{ip_address},{Mac_address},{device_name},{device_type},{operating_system},{opening_port},{online}\n'
        f.write(all_data)
    f.close()
if __name__ == '__main__':
    main()

以下是爬取成功的数据


第七题:

直接Ctrl+U 快捷键查看页面源代码 Ctrl+F搜索我们想要的数据

发现没有我们所需要的数据  此时为动态数据 为异步请求 由服务器返回给前端的数据

分析步骤 F12 打开开发者工具 Ctrl+R 刷新当前页面 点击网络 (Network) Ctrl+F 搜索数据

此时返回给我们数据所在的数据包 点进去即可

返回的是json格式的数据 

构建请求 模拟浏览器向服务器发送请求  拿到返回的json格式的数据

import requests
import pprint
url = 'https://spiderbuf.cn/web-scraping-practice/iplist'
headers = {
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "accept-encoding": "gzip, deflate, br, zstd",
    "cache-control": "no-cache",
    "cookie": "你的cookie",
    "pragma": "no-cache",
    "priority": "u=1, i",
    "referer": "https://spiderbuf.cn/web-scraping-practice/scraping-ajax-api",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
resp = requests.get(url, headers=headers)
print(resp.json())

打印之后发现 在终端会出现乱码  此时我们向之前那样处理 将accept-encoding 删掉 还是会这样

解决方法:

resp.encoding = resp.apparent_encoding

设置响应对象的编码格式
- `resp.encoding`:设置HTTP响应内容的解码方式
- `resp.apparent_encoding`:requests库自动检测到的内容编码格式
- 通过将两者相等,确保响应内容能以正确的编码方式进行解码,避免中文等非ASCII字符出现乱码问题

接着就是键值对取值了

lis = []
for li in resp.json():
    ip = li['ip']
    mac = li['mac']
    manufacturer = li['manufacturer']
    name = li['name']
    ports = li['ports']
    status = li['status']
    types = li['type']
    dit = {
        'ip': ip,
        'mac': mac,
        'manufacturer': manufacturer,
        'name': name,
        'ports': ports,
        'status': status,
        'types': types
    }
    lis.append(dit)
    pd.DataFrame(lis).to_excel('S_b_7.xlsx', index=False)
之前都是保存为csv文件 这次保存为xlsx文件
首先将字段存到字典当中 接着在外面定义一个空列表 将字典数据通过append方法加进去 最后通过pandas保存数据 别忘记导包

以下是爬取成功的数据图片


第八题:

分析可得 此页面是Post请求的静态数据  数据结构和第一题一样 把第一题的代码拿过来修改一下即可

找到对应的数据包查看携带的data

OK 开始写代码

import requests
from lxml import etree
# 修改地址
url = 'https://spiderbuf.cn/web-scraping-practice/scraper-via-http-post'
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    # "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "cookie": "你的cookie",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practices/1?order=learn",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
# 添加参数data
data = {
    "level": 8
}
resp = requests.post(url, headers=headers, data=data)
f = open('S_b_8.csv', 'w', encoding='utf-8-sig', newline='')
html = etree.HTML(resp.text)
lis = html.xpath('.//table[@class="table"]/tbody/tr')
f.write('number,ip_address,Mac_address,device_name,device_type,operating_system,opening_port,online\n')
for li in lis:
    number = ''.join(li.xpath('./td[1]/text()'))
    ip_address = ''.join(li.xpath('./td[2]/text()'))
    Mac_address = ''.join(li.xpath('./td[3]/text()'))
    device_name = ''.join(li.xpath('./td[4]/text()'))
    device_type = ''.join(li.xpath('./td[5]/text()'))
    operating_system = ''.join(li.xpath('./td[6]/text()'))
    opening_port = ''.join(li.xpath('./td[7]/text()'))
    if ',' in opening_port:
        opening_port = opening_port.replace(',', ',')
    if not opening_port:
        opening_port = '无'
    online = ''.join(li.xpath('./td[last()]/text()'))
    all_data = f'{number},{ip_address},{Mac_address},{device_name},{device_type},{operating_system},{opening_port},{online}\n'
    f.write(all_data)
f.close()


第九题:

解释 点击登录 才能看到数据 进而爬取数据

我们需要抓包 拿到api接口

首先 F12 打开开发者工具  点击网络(network)

如果下面由数据包 点击那个禁止的图标 目的是清楚当前所有的数据包

OK 登录成功我们可以看到返回的数据

在数据包中找跟登录有关的数据包

这里可以看到我们提交的信息  对此发请求即可

import requests
url = 'https://spiderbuf.cn/web-scraping-practice/scraper-login-username-password/login'
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "content-length": "30",
    "content-type": "application/x-www-form-urlencoded",
    "cookie": "你的cookie",
    "origin": "https://spiderbuf.cn",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practice/scraper-login-username-password",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
data = {
    'username': 'admin',
    'password': 123456,
}
resp = requests.post(url, headers=headers, data=data)
print(resp.text)

打印数据  查看我们的数据是否在其中

确定无误 对此页面数据提取

分析此结构可得 和第一题结构类似 拿第一题的代码过来修改即可

import requests
from lxml import etree
url = 'https://spiderbuf.cn/web-scraping-practice/scraper-login-username-password/login'
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "cache-control": "no-cache",
    "content-length": "30",
    "content-type": "application/x-www-form-urlencoded",
    "cookie": "你的cookie",
    "origin": "https://spiderbuf.cn",
    "pragma": "no-cache",
    "priority": "u=0, i",
    "referer": "https://spiderbuf.cn/web-scraping-practice/scraper-login-username-password",
    "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
}
data = {
    'username': 'admin',
    'password': 123456,
}
resp = requests.post(url, headers=headers, data=data)
f = open('S_b_9.csv', 'w', encoding='utf-8-sig', newline='')
html = etree.HTML(resp.text)
lis = html.xpath('.//table[@class="table"]/tbody/tr')
f.write('rank,value,company_info,CEO,industry\n')
for li in lis:
    rank = ''.join(li.xpath('./td[1]/text()'))
    value = ''.join(li.xpath('./td[2]/text()'))
    company_info = ''.join(li.xpath('./td[3]/text()'))
    CEO = ''.join(li.xpath('./td[4]/text()'))
    industry = ''.join(li.xpath('./td[5]/text()'))
    all_data = f'{rank},{value},{company_info},{CEO},{industry}\n'
    f.write(all_data)
f.close()


第十题:

需要我们输入验证码 然后点击登录 才能获取到数据

思路:先拿到获取验证码的api接口 数据包 然后在获取 登录成功的api

F12 打开开发者工具  Ctrl+R刷新当前页面

每次我们刷新 验证码就会变  在 工具栏这里 选择img 意思是筛选返回的数据包类型为图像的

在数据包中找到返回的图片 

然后分析此图片的Url 可以再次刷新页面对比两个的区别

发现就是.png前面的一串英文不同  现在就是看怎么才能拿到这一串英文

我们复制这一串 Ctrl+F 搜索  发现在请求这个页面中的源代码中有

OK 开始写代码 模拟浏览器服务器发送请求 解析提取 id=imgae的img标签提取里面的src属性

然后拼接图片的Url  发送请求 拿到图片的二进制数据 保存到本地

import requests
from lxml import etree
def get_resp(url):
    headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "cache-control": "no-cache",
        "cookie": "你的cookie",
        "pragma": "no-cache",
        "priority": "u=0, i",
        "referer": "https://spiderbuf.cn/web-scraping-practices/2?order=learn",
        "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\"",
        "sec-fetch-dest": "document",
        "sec-fetch-mode": "navigate",
        "sec-fetch-site": "same-origin",
        "sec-fetch-user": "?1",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
    }
    response = requests.get(url, headers=headers)
    return response

这里我们需要发三个请求 就写个函数方便些

# 程序入口
if __name__ == '__main__':
    url_1 = 'https://spiderbuf.cn/web-scraping-practice/web-scraping-with-captcha'
    resp = get_resp(url_1)
    # 这里我直接这样写了  将响应的图片地址提取出来 然后拼接成图片的url
    number_url = 'https://spiderbuf.cn' + etree.HTML(resp.text).xpath('.//img[@id="image"]/@src')[0]
    # 将图片保存 写入二进制数据
    with open('./img_S_b/yzm.png', 'wb') as f:
        f.write(get_resp(number_url).content)

OK 我们将图片保存到本地之后 需要将图片中的数字读取出来

这里有个免费的模块可以使用 ddddocr  带带弟弟

用法如下
先安装  pip install ddddocr
然后导入  import ddddocr

# 实例化一个对象
# 这个是有广告的 show_ad=False 关闭广告
ocr = ddddocr.DdddOcr(show_ad=False)
# 读取图片
with open('./img_S_b/yzm.png', 'rb') as f:
     numbers = ocr.classification(f.read())

我们可以看一下是否成功读取数字

OK  下一步 对登录的api接口发起请求

回到登录的页面  打开开发者工具 清楚当前所有的数据包(点击这个按钮)

然后输入验证码 点击登录 可以看到数据了

这个就是我们登录的数据包 可以Ctrl+F搜索 用户名 admin 搜到

分析可得 Post方法 data表单数据中 传入验证码  以及验证码的id 就是前面在网页源代码中提取的一串英文

# 图片的id
captchaId = number_url.split('/')[-1].split('.')[0]
    data = {
        "username": "admin",
        "password": "123456",
        "captchaSolution": f"{numbers}",
        "captchaId": f"{captchaId}"
    }
    log_url = 'https://spiderbuf.cn/web-scraping-practice/web-scraping-with-captcha/login'
    headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "cache-control": "no-cache",
        "content-length": "84",
        "content-type": "application/x-www-form-urlencoded",
        "cookie": "__check_once=zfaItN7y1h71fZjY; _ga=GA1.1.708657061.1763371540; __gads=ID=98ca5ab3854f8f7b:T=1763371542:RT=1765101346:S=ALNI_MarOlLEhFCBjKmYlgNY0raV9R7gNg; __gpi=UID=000011b788c64afc:T=1763371542:RT=1765101346:S=ALNI_Mbts5XM02bKGB6uNwuvlFoz8CPhqw; __eoi=ID=cd119b00af58d9e4:T=1763371542:RT=1765101346:S=AA-AfjbIBrUY97XhQd5DGDYSZ-on; _ga_7B42BKG1QE=GS2.1.s1765106320$o12$g0$t1765106320$j60$l0$h0",
        "origin": "https://spiderbuf.cn",
        "pragma": "no-cache",
        "priority": "u=0, i",
        "referer": "https://spiderbuf.cn/web-scraping-practice/web-scraping-with-captcha",
        "sec-ch-ua": "\"Chromium\";v=\"142\", \"Microsoft Edge\";v=\"142\", \"Not_A Brand\";v=\"99\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\"",
        "sec-fetch-dest": "document",
        "sec-fetch-mode": "navigate",
        "sec-fetch-site": "same-origin",
        "sec-fetch-user": "?1",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
    }
    inner_text = requests.post(log_url, data=data, headers=headers)
    print(inner_text.text)

验证码 以及图片的ID

这个验证码的模块 很多时候会识别不准确 推荐适用第三方打码平台 或者手动输入验证码

后面和上一题的解析是一样的 这里就不过多介绍了

之后再更新后面的题目


本次的案例分析就到此结束啦 谢谢大家的观看  你的点赞和关注是我更新的最大动力
如果感兴趣的话可以看看我之前的博客

posted @ 2026-01-08 15:17  clnchanpin  阅读(11)  评论(0)    收藏  举报