Beautiful Soup4爬虫速成

news2024/11/16 19:42:53

做毕业论文需要收集数据集,我的数据集就是文本的格式,而且是静态页面的形式,所以只是一个简单的入门。动态页面的爬虫提取这些比较进阶的内容,我暂时没有这样的需求,所以有这类问题的朋友们请移步。
如果只是简单的静态页面的信息爬取,我这篇文章的结构尽量做的清晰,并且把注释给打好,相信有点语法基础的都是能看懂的。

目录

  • URL管理器
  • Beautiful Soup4语法速成
    • 创建Beautiful Soup4对象
    • 搜索结点
    • 访问结点信息
  • 超简单爬虫案例
  • 进阶——爬取所有博客页面
    • 知识点掌握
    • 实战
  • 实践——爬取豆瓣电影Top250榜单

URL管理器

我们可能会爬取大量的URL,并且还可能对URL进行筛选,同时我们需要避免重复和循环爬取,所以对URL进行管理是重要的,具体的管理方式是这样的:
1、建立两个set数组,一个是new_urls存储未爬取的URL,一个是old_urls存储已爬取的URL;
2、如果一个网站是新的网站,那就存在new_urls中;
3、如果new_urls里的网站被爬取过了,那就在new_urls中删除这个网站,并且添加到old_urls中,利用new_urls与old_urls一起判断一个网站是否是一个新的网站。

在工程下面新建一个utils的包,并且将工具类直接封装在这个包下,代码如下:

# -- coding: utf-8 --
class UrlManager():
    """URL管理器"""
    def __init__(self):  # 初始化函数
        # old_urls的来源就是new_urls,爬取完就把URL从new_urls中删除并添加到old_urls中
        self.new_urls = set()  # 定义未爬取的URL的集合
        self.old_urls = set()  # 定义已经爬取了的URL的集合

    def add_new_url(self, url):  # 增加新的URL
        if url is None or len(url) == 0:  # 判断URL是否合格
            return
        if url in self.new_urls or url in self.old_urls:  # 判断是否出现过,不管是否是已经爬取了的,都不应该重复添加一个URL
            return
        self.new_urls.add(url)  # 如果是新的URL,就增加到未爬取的set数组中去

    def add_new_urls(self, urls):  # 增加批量的URL
        if urls is None or len(urls) == 0:  # 同理,批量的URL不合法就return
            return
        for url in urls:
            self.add_new_url(url)

    def get_url(self):  # 取出URL
        if self.has_new_url():  # 若有未爬取的URL
            url = self.new_urls.pop()  # 将new_urls移除一个元素并且返回
            self.old_urls.add(url)  # 爬取就把这个URL放到old_urls中
            return url
        else:
            return None

    def has_new_url(self):  # 判断是否有还未爬取的URL
        return len(self.new_urls) > 0


if __name__ == "__main__":  # 测试类
    url_manager = UrlManager()

    url_manager.add_new_url("url1")
    url_manager.add_new_urls(["url1", "url2"])
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    new_url = url_manager.get_url()
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    new_url = url_manager.get_url()
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    print(url_manager.has_new_url())

Beautiful Soup4语法速成

Beautiful Soup4是比较便捷的,比起一堆乱七八糟的正则表达式,这里只需要掌握一下语法就能随便做爬虫了,大家可以看官方的帮助文档:
Beautiful Soup4帮助文档
我这边就总结一些常用的:

创建Beautiful Soup4对象

from bs4 import BeautifulSoup
# 根据HTML网页字符串创建BeautifulSoup对象
soup = BeautifulSoup(
					html_doc,           # HTML文档字符串
					'html.parser',		# HTML解析器,平时就用这个就行
					from_encoding='utf8'# HTML文档的编码
					)

搜索结点

# 查找所有标签为a的结点
soup.find_all('a')

# 查找所有标签为a,链接符合/view/123.html形式的结点
soup.find_add('a', href='view/123.html')

# 查找所有标签为div,class为abc,文字为python的结点
soup.find_all('div', class_='abc', string='Python')  # 还可以根据id等信息查找对应标签,注意class后面有下划线,因为class是关键字

访问结点信息

# 假设得到了结点<a href='1.html'>Python</a>

# 标签名称
node.name

# a结点的href属性
node['href']

# a结点的链接文字
node.get_text()

超简单爬虫案例

网页代码右键+检查就能看了,学过web能看懂HTML代码就行。
流程很容易:
1、利用request获取网页内容
2、利用BeautifulSoup来解析内容

接下来我们利用爬虫来爬取静态的博客网站,这里就拿一些非主流网站,那些个主流网站应该都会拦截的,我没学那么复杂。
代码如下:

# -- coding: utf-8 --
import requests
from bs4 import BeautifulSoup

# 指定url为我的博客主页网址
url = "http://www.crazyant.net"

r = requests.get(url)  # 利用requests获取url信息
if r.status_code != 200:  # 状态值不为200则返回异常
    raise Exception()

# 获取url文本内容
html_doc = r.text

# 创建Beautiful Soup4对象
soup = BeautifulSoup(html_doc, "html.parser")

# 找到所有的h2标签,所有的文章链接跳转都放在了h2下面,这一点自行打开网页源代码就能看见了
h2_nodes = soup.find_all("h2", class_="entry-title")

for h2_node in h2_nodes:
    link = h2_node.find("a")  # 查找标签名为a的所有标签
    print(link["href"], link.get_text())  # 打印链接和标签名

运行结果:
在这里插入图片描述

进阶——爬取所有博客页面

感觉这个学会了基本就学会了如何爬取一个静态页面了。
还是上个例子的网址:
根域名:http://www.crazyant.net
文章页URL形式:http://www.crazyant.net/2261.html

知识点掌握

首先掌握一些知识点:
1、requests请求时附带cookie字典

import requests
cookies = {...}
r = requests.get(
	"http://url",
	cookies=cookies
)

2、正则表达式实现模糊匹配:

import re  # 正则表达式的包
url1 = "http://www.crazyant.net/123.html"
url2 = "http://www.crazyant.net/123.html#comments"
url3 = "http://www.baidu.com"

# 解析一下这个表达式
# 1、"^...$,那么结尾就必须得是.html的形式"
# 2、“\d”表示是数字,“\d+”表示是多个数字
pattern = r'^http://www.crazyant.net/\d+.html$'
print(re.match(pattern, url1))  # OK
print(re.match(pattern, url2))  # None
print(re.match(pattern, url3))  # None

实战

接下来进行实战

# -- coding: utf-8 --
import re

from utils import url_manager
import requests
from bs4 import BeautifulSoup

root_url = "http://www.crazyant.net"

urls = url_manager.UrlManager()
urls.add_new_url(root_url)

# 初始化文件对象,用于把结果写入文件中去,开启写入模式
fout = open("craw_all_pages.txt", "w", encoding="utf-8")

# 我们把跟URL添加以后,我们就可以进行爬取,并把新网址加入到new_urls中
while urls.has_new_url():  # 有未爬取的URL时为真
    curr_url = urls.get_url()
    # 获取网页内容,可能有很多网页,所以设置3秒反应时间
    r = requests.get(curr_url, timeout=3)
    if r.status_code != 200:
        print("error, return status_code is not 200", curr_url)
        continue
    soup = BeautifulSoup(r.text, "html.parser")  # 创建BeautifulSoup对象
    title = soup.title.string  # 获得title的值

    fout.write("%s\t%s\n" % (curr_url, title))  # 将网址和title写入文件
    fout.flush()  # 将内存数据刷到磁盘里,这样能很快看到数据
    print("success: %s, %s, %d" % (curr_url, title, len(urls.new_urls)))

    links = soup.find_all("a")  # 找到所有标签a内容
    for link in links:
        # 提取网址,并且与正则表达式进行匹配
        href = link.get("href")  # link["href"]有可能会错,因为有些超链接不标准,没有href
        if href is None:
            continue
        pattern = r'^http://www.crazyant.net/\d+.html$'
        if re.match(pattern, href):
            urls.add_new_url(href)  # 匹配那就写入

fout.close()

运行结果正常:
在这里插入图片描述

实践——爬取豆瓣电影Top250榜单

观察网站,10页,每页25个电影,我们要爬取10个页面的内容。
自行看一下网站的内容是怎样的,敲代码还是挺容易的。

# -- coding: utf-8 --
# 1、使用requests爬取网页
# 2、使用BeautifulSoup实现数据解析
# 3、借助pandas将数据写出到Excel
import requests
from bs4 import BeautifulSoup
import pprint
import pandas as pd
import json

# 下载共10个页面的HTML
page_indexs = range(0, 250, 25)  # 每个页面都是25个电影,因此间隔25
# print(list(page_indexs)): [0, 25, 50,...,200, 225]


def download_all_htmls():
    """下载所有页面的HTML,用于后续分析"""
    htmls = []
    for idx in page_indexs:
        url = f"https://movie.douban.com/top250?start={idx}&filter="
        print("craw html:", url)
        # 定义headers,绕开反爬机制
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
        r = requests.get(url, headers=headers)
        if r.status_code != 200:
            raise Exception("error")
        htmls.append(r.text)
    return htmls


# 执行爬取
htmls = download_all_htmls()


# 解析HTML得到数据
def parse_single_html(html):
    """解析单个HTML,得到数据,@return list({"link", "title", [label]})"""
    soup = BeautifulSoup(html, 'html.parser')  # 初始化对象
    article_items = (
        # 这里就自行观察一下网页的结构,就能定位到电影的位置
        soup.find("div", class_="article")
        .find("ol", class_="grid_view")
        .find_all("div", class_="item")  # 有多个,要find_all
    )
    datas = []
    for article_item in article_items:
        rank = article_item.find("div", class_="pic").find("em").get_text()
        info = article_item.find("div", class_="info")
        title = info.find("div", class_="hd").find("span", class_="title").get_text()
        stars = (
            info.find("div", class_="bd")
            .find("div", class_="star")
            .find_all("span")  # 有多个,要find_all
        )

        rating_star = stars[0]["class"][0]
        rating_num = stars[1].get_text()
        comments = stars[3].get_text()

        datas.append({
            "rank": rank,
            "title": title,
            "rating_star": rating_star.replace("rating", "").replace("-t", ""),
            "comments": comments.replace("人评价", "")
        })
    return datas


pprint.pprint(parse_single_html(htmls[0]))

# 执行所有的HTML页面的解析
all_datas = []
for html in htmls:
    all_datas.extend(parse_single_html(html))
# print(all_datas)

# 将结果存入Excel
df = pd.DataFrame(all_datas)
df.to_excel("豆瓣电影TOP250.xlsx")

运行结果:
在这里插入图片描述
如果我们想要查询电影榜单中每个电影的一些信息,我们可以爬取到网址以后直接爬取每个电影的网址,然后再提取相关的一些信息,掌握上面的一些内容,剩下都是基本功了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1276920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目标检测——Faster R-CNN算法解读

论文&#xff1a;Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks 作者&#xff1a;Shaoqing Ren, Kaiming He, Ross Girshick, and Jian Sun 链接&#xff1a;https://arxiv.org/abs/1506.01497 代码&#xff1a;https://github.com/rbgirsh…

vue使用elementui的el-menu的折叠菜单collapse

由于我的是在el-menu所在组件外面的兄弟组件设置是否折叠的控制&#xff0c;我用事件总线bus进行是否折叠传递 参数说明类型可选值默认值collapse是否水平折叠收起菜单&#xff08;仅在 mode 为 vertical 时可用&#xff09;boolean—falsebackground-color菜单的背景色&#…

深入理解Servlet(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 为什么要了解Servlet …

用JavaScript的管道方法简化代码复杂性

用JavaScript的管道方法简化代码复杂性 在现代 web 开发中&#xff0c;维护干净有效的代码是必不可少的。随着项目的增加&#xff0c;我们功能的复杂性也在增加。然而&#xff0c;javaScript为我们提供了一个强大的工具&#xff0c;可以将这些复杂的函数分解为更小的、可管理的…

什么是Anaconda

Anaconda的安装也很方便。打开这个网站Anaconda下载&#xff0c;然后安装即可。 Anaconda可以帮助我们解决团队之间合作的包依赖管理问题。在没有使用Anaconda之前&#xff0c;如果你的Python程序想让你的同事运行&#xff0c;那么你的同事可能会遇到很多包依赖问题&#xff0…

【 RTTI 】

RTTI 概念&#xff1a; RTTI(Run Time Type Identification)即通过运行时类型识别&#xff0c;程序能够使用基类的指针或引用来检 查着这些指针或引用所指的对象的实际派生类型。 原因&#xff1a; C是一种静态类 型语言。其数据类型是在编译期就确定的&#xff0c;不能在运…

2023年中国消费金融行业研究报告

第一章 行业概况 1.1 定义 中国消费金融行业&#xff0c;作为国家金融体系的重要组成部分&#xff0c;旨在为消费者提供多样化的金融产品和服务&#xff0c;以满足其消费需求。这一行业包括银行、消费金融公司、小额贷款公司等多种金融机构&#xff0c;涵盖了包括消费贷款在内…

力扣15题 三数之和 双指针算法

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三…

mysql的InnoDB存储引擎

详情请参考&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html InnoDB 是一个通用目的的存储引擎&#xff0c;它在高可用性、高性能方面做了平衡。MySQL 8.0&#xff0c;InnoDB 是默认的存储引擎。在创建表的时候&#xff0c;如果没有使用ENGIN…

1+x网络系统建设与运维(中级)-练习题

一.给设备重命名 同理可得&#xff0c;所有交换机和路由器都用一下命令配置 <Huawei>sys [Huawei]sysn LSW1 二.配置VLAN LSW1&#xff1a; [LSW1]vlan batch 10 20 [LSW1]int e0/0/1 [LSW1-Ethernet0/0/1]port link-type access [LSW1-Ethernet0/0/1]port default vlan…

用户反馈组件实现(Vue3+ElementPlus)含图片拖拽上传

用户反馈组件实现&#xff08;Vue3ElementPlus&#xff09;含图片拖拽上传 1. 页面效果1.1 正常展示1.2 鼠标悬浮1.3 表单 2. 代码部分1.2 html、ts1.2 less部分 3. 编码过程遇到的问题 1. 页面效果 1.1 正常展示 1.2 鼠标悬浮 1.3 表单 2. 代码部分 1.2 html、ts <templ…

gorm修改操作中两个update方法的小细节

在使用gorm进行修改操作时&#xff0c;修改操作中如下两个方法&#xff1a; Update() Updates() 都可以实现修改&#xff0c;根据名称可以看出Update是针对单个字段&#xff0c;而后者应该是多个。 下面是主要实际操作&#xff1a; ​​ Updates() 即&#xff0c;前者确实是…

vector是如何扩容的

vector容器扩容 vector是成倍扩容的&#xff0c;一般是2倍。 vector管理内存的成员函数 开始填值 没有填值之前&#xff0c;vector元素个数和容量大小都为0 加入一个值之后&#xff1a; 加入两个值&#xff1a;重点在加入三个值&#xff0c;此时容量变为4&#xff1a;加入第…

开源图床Qchan本地部署远程访问,轻松打造个人专属轻量级图床

文章目录 前言1. Qchan网站搭建1.1 Qchan下载和安装1.2 Qchan网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar云端设置2.2 Cpolar本地设置 3. 公网访问测试总结 前言 图床作为云存储的一项重要应用场景&#xff0c;在大量开发人员的努力下&#xff0c;已经开发出大…

优彩云采集器最新版免费下载,优彩云采集器免费

随着网络时代的发展&#xff0c;SEO&#xff08;Search Engine Optimization&#xff0c;搜索引擎优化&#xff09;已经成为网站推广和营销的关键一环。在SEO的世界里&#xff0c;原创内容的重要性愈发凸显。想要做到每天更新大量原创文章&#xff0c;并不是一件轻松的事情。优…

RocketMQ主从同步原理

一. 主从同步概述 主从同步这个概念相信大家在平时的工作中&#xff0c;多少都会听到。其目的主要是用于做一备份类操作&#xff0c;以及一些读写分离场景。比如我们常用的关系型数据库mysql&#xff0c;就有主从同步功能在。 主从同步&#xff0c;就是将主服务器上的数据同步…

接口测试基础知识

一、接口测试简介 什么是接口测试&#xff1f; 接口测试是测试系统组件间接口的一种测试&#xff0c;主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。 测试的重点&#xff1a; 检查数据的交换&#xff0c;传递和控制管理过程&#xff1b;检查系统间的相互…

人工智能对我们的生活影响有多大?

一、标题解析 本文标题为“人工智能对我们的生活影响有多大&#xff1f;”&#xff0c;这是一个典型的知乎风格SEO文案标题&#xff0c;既能够吸引读者&#xff0c;又能够体现文章的核心内容。 二、内容创作 1. 引言&#xff1a;在开头&#xff0c;我们可以简要介绍人工智能…

PVE系列-LVM安装MacOS的各个版本

PVE系列-LVM安装MacOS的各个版本 环境配置大概过程&#xff1a;详细步骤&#xff1a;1.建立安装环境和下载安装工具2. 重启后&#xff0c;执行osx-setup配置虚拟机3. 安装到硬盘&#xff0c;4.设定引导盘&#xff0c;以方便自动开机启动5.打开屏幕共享和系统VNC最后的结果 引子…

【Node.js】基础梳理 6 - MongoDB

写在最前&#xff1a;跟着视频学习只是为了在新手期快速入门。想要学习全面、进阶的知识&#xff0c;需要格外注重实战和官方技术文档&#xff0c;文档建议作为手册使用 系列文章 【Node.js】笔记整理 1 - 基础知识【Node.js】笔记整理 2 - 常用模块【Node.js】笔记整理 3 - n…