增量式爬虫的讲解与具体实现

今天在这里分享一些关于爬虫技术的介绍,主要以增量式爬虫介绍为主。

一、爬虫概念

所谓爬虫,其本质是一种计算机程序,它的行为看起来就像是蜘蛛在网上面爬行一样,顺着互联网这个“网”,一条线一条线地“爬行”。所以爬虫在英文中又叫作“Spider”,正是蜘蛛这个单词。
爬虫的主要目的是获取网页内容并解析
在互联网发展的势头下,各种开发技术变得日新月异,面对不同场景的需求衍生了类型众多的网络爬虫。网络爬虫按照系统结构实现技术大致可以分为4种类型,分别是通用网络爬虫聚焦网络爬虫增量式网络爬虫(广度优先)深层网络爬虫(深度优先)

有关其它爬虫技术,请参考:【由浅入深】爬虫技术,值得收藏,来了解一下~

1.1、增量式爬虫

增量式网终爬虫(Incremental Web Crawler)是指对已下载的网页采取增量式更新,只抓取新产生或者已经发生变化的网页的网络爬虫。
增量式网络爬虫只会抓取新产生的或内容变化的网页,并不会重新抓取内容未发生变化的网页,这样可以有效地减少网页的下载量,减少访问时间和存储空间的耗费,但是增加了网页抓取算法的复杂度和实现难度。

1.2、深层爬虫

深层网络爬虫(Deep Web Crawler)是指抓取深层网顷的网络爬虫,它要抓取的网页层次比较深,需要通过一定的附加策略才能够自动抓取,实现难度较大。

二、增量式爬虫的实现步骤

编写增量爬虫的一般步骤如下:

  1. 定义一个数据存储结构,记录已经爬取过的网页和相关信息,比如最后访问时间、页面内容哈希等。可以使用数据库或文件系统等方式进行存储。

  2. 确定需要爬取的网站,设计好爬虫的起始点。

  3. 从起始点开始爬取页面,并从页面中提取需要的信息。

  4. 对提取到的信息进行处理和存储,同时更新已经爬取过的页面的相关信息。

  5. 针对更新过的页面和可能的新页面,重复以上步骤,直到完成所有的爬取任务。

  6. 可以添加一些限制条件,比如爬取深度、爬取速度等,以避免给目标网站造成过大的负担。

需要注意的是,增量爬虫需要针对已经爬取过的页面进行更新和去重,可以根据页面的哈希值或者其他唯一标识进行比较和判断。同时,增量爬虫可能需要处理一些更新频率较高的页面,需要根据实际情况进行设计和优化。

三、增量式爬虫案例

下面是一个简单的增量式爬虫案例,用于从某个新闻网站抓取新闻文章的标题和链接,并实现增量爬取功能:

import requests
import hashlib
import time
import pymysql
from bs4 import BeautifulSoup

# 定义爬虫起始点和目标站点
start_url = 'https://news.example.com'
target_site = 'example.com'

# 定义数据库连接和数据表结构
conn = pymysql.connect(host='localhost', user='root', password='password', database='news_db', charset='utf8mb4')
cursor = conn.cursor()
cursor.execute('''
    CREATE TABLE IF NOT EXISTS news (
        id INT PRIMARY KEY AUTO_INCREMENT,
        title TEXT,
        url TEXT,
        hash TEXT,
        last_modified BIGINT
    )
''')

# 定义页面哈希函数
def get_hash(url, content):
    return hashlib.sha1(f'{
      
      url}{
      
      content}'.encode('utf-8')).hexdigest()

# 定义页面访问函数
def fetch_page(url):
    response = requests.get(url)
    if response.status_code == 200:
        return response.text
    else:
        return None

# 定义页面解析函数
def parse_page(content):
    soup = BeautifulSoup(content, 'html.parser')
    news_list = soup.find_all('a', {
    
    'class': 'news-link'})
    for news in news_list:
        title = news.text.strip()
        url = news['href'].strip()
        yield (title, url)

# 定义增量爬取函数
def crawl_incremental():
    last_modified = None
    cursor.execute('SELECT MAX(last_modified) FROM news')
    row = cursor.fetchone()
    if row[0]:
        last_modified = row[0]
    current_url = start_url
    while True:
        content = fetch_page(current_url)
        if content is None:
            break
        hash_value = get_hash(current_url, content)
        if hash_value in visited_urls:
            break
        visited_urls.add(hash_value)
        for title, url in parse_page(content):
            if target_site in url:
                cursor.execute('SELECT * FROM news WHERE url = %s', (url,))
                row = cursor.fetchone()
                if row:
                    # 已经爬取过该页面,检查是否需要更新
                    if row[4] < last_modified:
                        # 页面已经更新,重新爬取
                        cursor.execute('DELETE FROM news WHERE url = %s', (url,))
                        conn.commit()
                        crawl_url(url)
                    else:
                        # 页面没有更新,跳过
                        pass
                else:
                    # 第一次爬取该页面
                    cursor.execute('INSERT INTO news (title, url, hash, last_modified) VALUES (%s, %s, %s, %s)',
                                   (title, url, get_hash(url, fetch_page(url)), int(time.time())))
                    conn.commit()
        current_url = get_next_url(content)

# 定义获取下一个页面链接的函数
def get_next_url(content):
    # 略去具体实现
    pass

# 开始爬取
visited_urls = set()
crawl_incremental()

# 关闭数据库连接
conn.close()

具体来说,增量爬取函数crawl_incremental()中,我们通过查询数据库中已有的新闻页面的最后修改时间,以及使用SELECT语句检查数据库中是否已有某个页面的记录,来实现增量爬取。如果数据库中已有该页面的记录,就检查该页面的最后修改时间,如果该时间早于已有的最后修改时间,则说明页面已经更新,需要重新爬取,否则跳过。如果数据库中没有该页面的记录,则说明该页面是新页面,需要将其插入到数据库中。

需要注意的是,MySQL数据库的操作需要建立连接、打开游标、提交事务等步骤,因此需要在合适的地方进行相关操作,确保数据能够正确地插入或删除。另外,MySQL数据库需要指定字符集,以支持中文等非ASCII字符的存储和查询,因此需要在连接数据库时指定字符集为utf8mb4。

综上所述,以上是一个使用MySQL数据库实现增量爬虫的示例代码。实际应用中,需要根据具体的爬取需求和数据存储方式进行相应的修改和优化。

注意:
yield是Python中的关键字,用于生成器函数中的语句。当函数执行到yield语句时,会返回一个值,并暂停函数的执行,等待下一次调用时继续执行。因此,生成器函数可以返回多个值,并且每次返回一个值时可以暂停函数的执行,避免一次性生成所有值所带来的性能问题。

在上面的代码中,parse_page函数是一个生成器函数,用于解析新闻网站的HTML页面,返回新闻标题和链接。当调用parse_page函数时,它并不会一次性返回所有新闻标题和链接,而是通过yield关键字逐个返回。具体来说,parse_page函数会首先使用BeautifulSoup库解析HTML页面,然后通过find_all方法找到所有<a class="news-link">元素,再逐个提取元素的text和href属性作为新闻标题和链接,并通过yield关键字逐个返回。在爬虫函数中,可以通过for … in …循环逐个遍历parse_page函数的返回值,获得每个新闻的标题和链接,并进行后续的处理。

总之,yield关键字是生成器函数中的重要语句,它可以使函数的返回值逐个生成并返回,避免一次性生成所有值所带来的性能问题,也方便进行迭代处理

猜你喜欢

转载自blog.csdn.net/qq_44723773/article/details/129051978