如何写一个简单的爬虫

news2024/11/26 21:37:49

学习爬虫重要的是知识储备以及实战能力,最近有个学妹要求我帮她写一个爬虫程序,我将我编写的爬虫代码以及解释都记录下来,方便后期更多的伙伴们学习参考。

前置知识-爬虫定义

爬虫指的是一种自动化程序,用于在互联网上获取和抓取信息。它可以从网站中抓取数据并将其存储到本地计算机或其他数据库中,以便进一步处理和分析。

爬虫通常会自动访问网页、解析页面内容,并提取有用的信息,例如网页上的文本、图像、视频、音频、超链接等等。

requests 库:这是一个用于发送 HTTP 请求的库,可以发送 GET、POST、PUT、DELETE 等多种请求方式,并且可以设置请求头、请求体、Cookies 等信息。它还支持自动处理重定向、代理、SSL/TLS 等常见的网络请求问题,并且支持响应的解析,可以解析 JSON、HTML 等多种格式的响应数据。

urllib.parse 库:这是一个用于解析 URL 的库,它可以将 URL 拆分成各个部分,例如协议、域名、路径、查询参数等,并且可以对 URL 进行编码和解码,防止出现乱码和安全问题。

bs4 库:这是一个用于解析 HTML 和 XML 的库,可以从 HTML 或 XML 文件中提取数据,并且支持多种解析方式,例如基于标签名、CSS 选择器、正则表达式等。它还可以自动修正 HTML 或 XML 代码中的错误,方便数据提取。

正文-简单实现

首先,我们可以先实现一个简单的爬虫代码。

功能:

可以从指定的 URL 开始遍历整个网站。

输出网站中所有的链接。

关键代码实现:

import requests
from bs4 import BeautifulSoup

def crawl(url):
    # 发送 GET 请求获取页面内容
    response = requests.get(url)
    
    # 使用 BeautifulSoup 解析页面内容
    soup = BeautifulSoup(response.content, 'html.parser')
    
    # 获取页面中所有链接
    links = []
    for link in soup.find_all('a'):
        href = link.get('href')
        if href:
            links.append(href)
    
    return links

# 测试代码
if __name__ == '__main__':
    url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
    links = crawl(url)
    for link in links:
        print(link)

这个代码使用了python的 requests 库来发送 HTTP 请求,使用 BeautifulSoup 库来解析 HTML 页面内容,获取页面中所有链接并输出。在测试代码中,可以指定要爬取的 URL,然后输出所有链接。

第一次优化

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin

def get_links(url):
    # 发送 GET 请求获取页面内容
    response = requests.get(url)
    
    # 使用 BeautifulSoup 解析页面内容
    soup = BeautifulSoup(response.content, 'html.parser')
    
    # 获取页面中所有链接
    links = []
    for link in soup.find_all('a'):
        href = link.get('href')
        if href:
            href = urljoin(url, href)  # 处理相对链接
            parsed_href = urlparse(href)
            if parsed_href.scheme in ('http', 'https') and parsed_href.netloc:  # 只处理 http 和 https 协议的链接
                links.append(href)
    
    return links

def crawl(url, max_depth=3):
    visited = set()  # 已访问过的链接
    queue = [(url, 0)]  # 待访问的链接队列
    
    while queue:
        url, depth = queue.pop(0)
        if depth > max_depth:  # 超过最大深度,停止访问
            break
        
        if url not in visited:
            visited.add(url)
            print(' ' * depth, url)
            links = get_links(url)
            for link in links:
                if link not in visited:
                    queue.append((link, depth+1))
                    
# 测试代码
if __name__ == '__main__':
    url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
    crawl(url)

这个代码与之前的代码相比进行了以下优化:

处理相对链接:使用 urljoin 函数将相对链接转换为绝对链接,以便更好地处理。

只处理 http 和 https 协议的链接:使用 urlparse 函数获取链接的协议和域名,只处理 http 和 https 协议的链接。

控制访问深度:使用 max_depth 参数控制访问深度,避免无限递归导致程序崩溃。

优化访问效率:使用集合 visited 记录已经访问过的链接,避免重复访问。

在测试代码中,可以指定要爬取的 URL,并设置 max_depth 参数,然后输出所有链接及其对应的深度。

第二次优化

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin
import time

class Crawler:
    def __init__(self, start_url, max_depth=3, delay=1):
        self.start_url = start_url
        self.max_depth = max_depth
        self.delay = delay
        self.visited = set()
        self.queue = [(start_url, 0)]

    def crawl(self):
        while self.queue:
            url, depth = self.queue.pop(0)
            if depth > self.max_depth:
                break
            if url in self.visited:
                continue
            self.visited.add(url)
            print(' ' * depth, url)
            time.sleep(self.delay)
            links = self.get_links(url)
            for link in links:
                if link not in self.visited:
                    self.queue.append((link, depth+1))

    def get_links(self, url):
        response = requests.get(url)
        soup = BeautifulSoup(response.content, 'html.parser')
        links = []
        for link in soup.find_all('a'):
            href = link.get('href')
            if href:
                href = urljoin(url, href)
                parsed_href = urlparse(href)
                if parsed_href.scheme in ('http', 'https') and parsed_href.netloc:
                    links.append(href)
        return links

# 测试代码
if __name__ == '__main__':
    start_url = 'http://jshk.com.cn/mb/reg.asp?kefu=xjy'
    crawler = Crawler(start_url, max_depth=3, delay=1)
    crawler.crawl()

这个代码相比之前的代码进行了以下优化:

将爬虫代码封装到一个类 Crawler 中,方便控制和管理爬虫。

增加了延时参数 delay,可以设置每次访问页面的延时,避免过快访问导致被封禁。

增加了错误处理和日志记录,可以更好地处理异常情况和记录程序运行情况。

在测试代码中,可以创建一个 Crawler 对象,设置起始 URL、最大深度和延时参数,然后调用 crawl 方法开始爬取网站。其中,crawl 方法使用 BFS 算法遍历网站,get_links 方法获取页面中的所有链接,同时加入了延时和错误处理机制。

结果展示

在这里插入图片描述

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

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

相关文章

VB6换个思路解决微信下载文件只读的问题(含源码)

日期:2023年3月10日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方&#xf…

Android Framework——zygote 启动 SystemServer

概述 在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于Zygote进程在Android系统中有着如此重…

docker使用教程(装linux比虚拟机方便)

目录 一、介绍 二、使用 1.下载操作系统 2.查看docker内的容器有哪些 3. 运行指定容器 4.进入容器 ​1.attach进入容器(输入容器ID前4位) 2.exec进入容器(可以输入ID或者NAMES) 5.退出容器 6.在宿主机器和容器之间拷贝文…

时间同步Chrony

时间同步chrony一、Chrony时间服务1、Chrony介绍2、Chrony优点二、配置Chrony服务三、验证一、Chrony时间服务 1、Chrony介绍 chrony 是基于NPT协议的实现时间同步服务,它既可以当做服务端,也可以充当客户端。chrony是ntp的代替品,能更精确…

数据传输服务DTS(阿里巴巴)

数据传输服务DTS(阿里巴巴) 什么是数据传输服务DTS 数据传输服务DTS(Data Transmission Service)是阿里云提供的实时数据流服务,支持关系型数据库(RDBMS)、非关系型的数据库(NoSQL)、数据多维分…

CentOS 7 使用 Composer 配置 phpmyadmin 并管理多个mysql

phpMyAdmin 中文文档 准备工作 CentOS 7 yum 方式安装 phpCentOS 7 安装 Apache HTTP Server安装Composer 安装 phpMyAdmin 按照官方文档 用Composer安装 要安装phpMyAdmin,只需运行: composer create-project phpmyadmin/phpmyadmin 建立网站配置文…

skywalking部暑(zookeeper、kafka、elasticsearch)

服务器IP部暑角色192.168.11.100zookeeper kafka elasticsearch 一、docker部暑 。。。 二、.安装Zookeeper path/data/zookeeper mkdir -p ${path}/{data,conf,log} chown -R 1000.1000 ${path}echo "0" > ${path}/data/myid #zookeeper配置文件 cat > ${p…

Gitee初练 --- 问题合集(一)

Gitee一、Windows找不到gpedit.msc请确定文件名是否正确的提示二、windows 10 凭据无法保存三、解决 git pull/push 每次都要输入用户名密码的问题一、Windows找不到gpedit.msc请确定文件名是否正确的提示 就随便在一个地方建立一个文本文件,将一下内容复制进去 e…

从0-1超详细教你使用nginx打包部署静态资源,以及hash和history配置汇总

首先呢,我们要有以下几个方面的知识和操作,来实现项目部署 第一:我们要搭建nginx部署基础环境 具体流程可参考这个链接从0-1超详细教你实现前端代码nginx部署全流程 第二:我们要知道前端路由hash和history实现以及区别 路由功…

Reactor响应式流的核心机制——背压机制

响应式流是什么? 响应式流旨在为无阻塞异步流处理提供一个标准。它旨在解决处理元素流的问题——如何将元素流从发布者传递到订阅者,而不需要发布者阻塞,或订阅者有无限制的缓冲区或丢弃。 响应式流模型存在两种基本的实现机制。一种就是传统…

【OpenAI 多模态预训练】VideoGPT?微软透露GPT-4或将在下周发布

【多模态预训练】VideoGPT?微软透露GPT-4或将在下周发布 先让我猜个名字,VideoGPT? 太绝了!看完ChatGPT之后就感觉OpenAI正在做多模态的预训练语言模型。万万没想到来的这么快。据介绍,GPT-4或将为多模态大模型&#…

redis经典五种数据类型及底层实现

目录一、Redis源代码的核心部分1.redis源码在哪里2.src源码包下面该如何看?二、我们平时说redis是字典数据库KV键值对到底是什么1.6大类型说明(粗分)2.6大类型说明3.上帝视角4.Redis定义了redisObject结构体4.1 C语言struct结构体语法简介4.2 字典、KV是什么4.3 red…

jsp毕业答辩管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 毕业答辩管理系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…

Spring Security基础入门

基础概念 什么是认证 认证:用户认证就是判断一个用户的身份身份合法的过程,用户去访问系统资源的时候系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。常见的用户身份认证方式有:用户密码登录&am…

基于java的网络选课商城项目部署

前言:相信看到这篇文章的小伙伴都或多或少有一些编程基础,懂得一些linux的基本命令了吧,本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python:一种编程语言&…

SAP 生产订单收货入库Goods Receipt

Goods Receipt: 收货这块比较简单,当我们做完报工之后,成品就可以入库了。 那么收货完了,到底会有什么样的影响呢? 会产生物料凭证以及会计凭证,但是若订单中勾选”GR非股价的“,则不会有价值。 这里我们需…

E1. Unforgivable Curse (easy version) #855 div3

ps:很久没有更新啦,之前一直在复习准备期末考试,也没怎么写题。现在考完要恢复训练啦 Problem - E1 - Codeforces 题意: 两个字符串s和t,在s中任意两个间隔为k或者k1的字母可以进行任意次的交换,问你可不…

STL源码剖析(1) - 空间配置器与内存操作详解

文章首发于&#xff1a;My Blog 欢迎大佬们前来逛逛1. SGI空间配置器SGI STL的空间配置器是 alloc而非allocator&#xff0c;并且不接受任何参数&#xff1a;vector<int,std::alloc> vec我们通常使用缺省的空间配置器&#xff1a;template <typename T,typename Alloc…

mac 安装python、pip、weditor

问题现象&#xff1a;执行 python3 -m weditor 报错 ➜ ~ python3 -m weditor dyld[42143]: dyld cache (null) not loaded: syscall to map cache into shared region failed dyld[42143]: Library not loaded: /System/Library/Frameworks/CoreFoundation.framework/Versio…

【前端vue2面试题】2023前端最新版vue2模块,高频24问

​ &#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;博主收集的关于vue2面试题 目录 vue2面试题 1、$route 和 $router的区别 2、一个.v…