如何写一个简单的爬虫

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

前置知识-爬虫定义

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

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

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 方法获取页面中的所有链接,同时加入了延时和错误处理机制。

结果展示

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值