爬虫如何避免网页重复爬取

    在使用爬虫爬取网页信息的时候,如果只爬取固定的网页还好,但是如果从一个网页的源码中解析出其他的链接,爬虫爬取到其他的网页,这样就会出现一个问题,如何确定这个网页我爬取过,如何设置爬取的网页不再爬取。

    本篇文章实现避免重复爬取的思路是:将爬取过的网页的链接和该网页的信息以键值对的形式保存到数据库中,当爬虫爬取一个网页之前,先从数据库中查找是否有该网页的爬取记录,如果有该网页的爬取记录,那么就说明该网页已爬取过,就不需要再爬取该网页了,否则就证明这个网页没有爬取过,继而爬取这个网页的内容。

使用Mongodb数据库

    因为Mongodb数据库是文档型数据库,因此在实现避免重复爬取的机制中我们可以将网页的链接作为key,将网页爬取的内容作为value存储到数据库中,每一个链接对应该链接爬取的内容,这样在爬取一个新的链接就能从数据库中查找该链接是否已经爬取过。因此在这里需要使用Mongodb数据库来保存爬取的链接与爬取的内容。

python连接Mongodb数据库需要用到pymongo,没有安装可以使用pip install pymongo安装。Mongodb安装也很简单,这里我就不介绍Mongodb数据库的安装方法了。

代码思路:1.初始化设置各种参数,连接数据库 2.重写__setitem__方法将爬取的链接与内容以键值对的形式存储到数据库3. 重写__getitem__方法,用来查询爬取的链接对应的内容 4.重写__contains__,用来判断数据库中是否存在需要爬取的链接5.删除数据库,清除数据。

from pymongo import MongoClient
from datetime import datetime,timedelta
from bson.binary import Binary
import pickle,zlib


class MongoCache:
    def __init__(self,expires=timedelta(days=30)):
        """
        初始化,设置各种基本参数
        :param expires: 设置过期时间
        """
        self.client = MongoClient('localhost',27017)
        self.db = self.client.practice
        self.collection = self.db.htmlpage
        # 创建索引
        self.collection.create_index('timestamp',expireAfterSeconds=expires.total_seconds())

    def __setitem__(self, key, value):
        """
        将爬取的内容序列化压缩并以binary格式存储到数据库中
        :param key: 爬取的链接
        :param value: 对应链接爬取的结果
        :return:
        """
        record = {'result':Binary(zlib.compress(pickle.dumps(value))),'timestamp':datetime.utcnow()}
        self.collection.update({"_id":key},{'$set':record},upsert=True)

    def __getitem__(self, item):
        """
        通过链接获取到对应链接爬取的结果
        :param item: 链接地址
        :return: 解压缩并反序列化后的结果
        """
        record = self.collection.find({"_id":item})
        if record:
            return zlib.decompress(pickle.loads(record['result']))
        else:
            raise KeyError(item + 'does not exists')

    def __contains__(self, item):
        """
        判断数据库中是否存有该链接地址的信息,如果没有则返回False
        :param item:
        :return:
        """
        try:
            self[item]
        except KeyError:
            return False
        else:
            return True

    def clear(self):
        self.collection.drop()

这里只定义了避免网页重复爬取的接口,那么我们可以使用上次爬取糗事百科的代码来调用这个接口,实现避免网页重复爬取。

import requests
import lxml.html
from practice import MongoCache

class QiuBaiSpider():
    def __init__(self):
        self.base_url = 'https://www.qiushibaike.com/8hr/page/{}/'

    def make_download_list(self,page):
        return [self.base_url.format(i) for i in range(page[0],page[1]+1)]

    def download_content(self,url):
        result = requests.get(url)
        html = lxml.html.fromstring(result.text)
        content = html.xpath('//div[@class="content"]/span/text()')
        return content

    def run(self,page):
        # 生成下载列表
        download_list = self.make_download_list(page)
        mongo_cache = MongoCache()
        # 查询已有文档
        result = mongo_cache.collection.find()
        exist_id = []
        # 查询到的是结果集,只有每个结果才有_id属性
        for url in result:
            # 将所有已爬取过的网页链接放在临时列表中,也就是_id字段
            exist_id.append(url["_id"])
        for download_url in download_list:
            # 如果该链接在数据库中存在,说明已爬取过,将不再爬取
            if download_url not in exist_id:
                content = self.download_content(download_url)
                print(content)
                mongo_cache[download_url] = content
        print('爬取结束')

if __name__ == '__main__':
    qiubai = QiuBaiSpider()
    qiubai.run([1,12])

因为这次我们将数据保存到了Mongodb数据库中,因此保存到文件以及生成对应页码的文件名代码就没有用了,这里就没写。这里可以试验一下,第一次爬取1-5页的数据,第二次爬取1-8页的数据,第二次爬取由于1-5页的数据在数据库中已经存在,所以爬虫将不再爬取前五页的数据,而是直接爬取6-8页。

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
爬取豆瓣图书网页的翻页数据,可以使用 Python 的 requests 库和 BeautifulSoup 库来实现。 具体步骤如下: 1. 导入需要的库: ```python import requests from bs4 import BeautifulSoup ``` 2. 定义要爬取网页链接和请求头: ```python url = 'https://book.douban.com/top250' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} ``` 3. 发送 HTTP 请求获取网页内容: ```python response = requests.get(url, headers=headers) ``` 4. 使用 BeautifulSoup 解析网页内容,并找到需要的翻页信息: ```python soup = BeautifulSoup(response.text, 'html.parser') next_page = soup.find('span', class_='next').find('a')['href'] ``` 5. 处理翻页链接,获取下一页的网页内容: ```python next_url = url + next_page response = requests.get(next_url, headers=headers) ``` 6. 重复以上步骤,直到获取所有需要的数据。 完整代码示例: ```python import requests from bs4 import BeautifulSoup url = 'https://book.douban.com/top250' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} while url: response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') # 处理数据 next_page = soup.find('span', class_='next').find('a') if next_page: url = url + next_page['href'] else: url = None ``` 其中,while 循环中的代码用于处理每一页的数据,并判断是否存在下一页。如果存在下一页,则将 url 修改为下一页的链接,继续处理下一页的数据。如果没有下一页,则将 url 设置为 None,结束循环。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值