爬虫第四式:增量爬虫之爬取汽车之家数据

今天我们实现增量爬虫~,先来了解一下啥是增量爬虫??

增量爬虫: 通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据

通俗来讲:就是当你在爬取一个网站的数据的时候,反反复复在爬取,比如现在有一个项目,需要你用爬虫爬取某网站的数据

但是这个爬虫不能每次都运行,都是从头到尾爬取数据吧,这也不利于高效率开发啊,而且,就算每次都爬取,那爬取的数据是不是有很多重合的

你昨天爬过一次,今天再爬,是不是昨天爬过的数据又是在重新爬取了?这样就会造成数据的冗余,所以就有了增量爬虫的到来

对他的定义我觉得就是懒爬取,因为就是我们在第一爬去数据的时候,爬取完毕后,再次启动爬虫程序,只要是那个网站没有跟新的数据,他就不会爬,一旦有了更新,他也只是爬取更新的数据,之前爬过的数据一律不再爬取,这样就节省了工作效率,更不会造成数据冗余
说了这么多,希望大家可以明白增量爬虫的意义所在,好了,我们接下来准备一下环境吧

项目环境

1、建立自己的User-Agent池
这个有必要说明一下,以前呢,我们是自己去网上搜User-Agent,或者用浏览器的,
我们本次爬虫就用这个,这个是随机的User-Agent,只需要导入包就可以用了,简单快捷说一下怎么安装:
	1)pip3 install fake_useragent #安装
	2)from fake_useragent import UserAgent  #导入
	   UserAgent().random   # 使用
2、pymongo
	这个是MongoDB数据库(可有可无),不存数据库的可以不用了,这个不影响增量爬虫
3、redis
	这个是实现增量爬虫的必须品,redis数据库,这个属于缓存型数据库,他是建立在内存中的数据库
4、hashlib
	Python里面的hashlib模块提供了很多加密的算法,我们这次用hashlib的md5算法加密数据
5、requests
	pip install requests #安装
	requests是python实现的简单易用的HTTP库,使用起来比urllib简洁很多

好了,所需环境就这么多,就下来我们看一下怎么做了:

汽车之家二手车数据抓取
一、分析:
    1. 一级页面: 每辆汽车详情页的链接
    2. 二级页面: 每辆汽车具体的数据
二、建立自己的User-Agent池:
    2. from fake_useragent import UserAgent
       UserAgent().random
三、使用redis中集合实现增量爬虫
    原理: 根据sadd()的返回值来确定之前是否抓取过
        返回值为1: 说明之前没有抓取过
        返回值为0: 说明之前已经抓取过,程序结束

接下来就是代码展示了:

导入各种会用到的包

import requests
import re
import time
import random
from fake_useragent import UserAgent  
import pymongo
import redis  # 增量就靠它
from hashlib import md5   #加密算法库
import sys

总体的思路还是:定义功能函数,减少重复代码

class CarSpider:
    def __init__(self):
        self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/?pvareaid=102179#currengpostion'
        # mongodb3个对象
        # 连接mongodb数据库
        self.conn = pymongo.MongoClient('localhost', 27017)
        self.db = self.conn['cardb']
        self.myset = self.db['carset']
        # 连接到redis
        self.r = redis.Redis(host='localhost', port=6379, db=0)

功能函数1: 请求功能函数
’User-Agent’: UserAgent().random 这个就是创建随机的User-Agent池

def get_html(self, url):
    headers = {'User-Agent': UserAgent().random}
    # ignore参数: 解码时遇到不识别的字符直接忽略掉
    html = requests.get(url=url, headers=headers).content.decode('gb2312', 'ignore')

    return html

功能函数2: 解析功能函数,获取到的数据,进行用正则解析出来

def re_func(self, regex, html):
	pattern = re.compile(regex, re.S)
	r_list = pattern.findall(html)
	
	return r_list

"功能函数: 对url进行md5加密,加密的作用就是对每个数据加密,避免重复数据

def md5_url(self, url):
    s = md5()
    s.update(url.encode())

    return s.hexdigest()

爬虫逻辑函数

def parse_html(self, one_url):
    """爬虫逻辑函数"""
    one_html = self.get_html(url=one_url)
    one_regex = '<li class="cards-li list-photo-li".*?<a href="(.*?)".*?</li>'
    # href_list: ['/declear/xxx.html', '', '', '', ...]
    href_list = self.re_func(one_regex, one_html)
    for href in href_list:
        finger = self.md5_url(href)
        # 返回值1:之前没抓过
        if self.r.sadd('car:spiders', finger) == 1:
            # 拼接完整URL地址,发请求提取具体汽车信息
            self.get_one_car_info(href)
            time.sleep(random.randint(1, 2))
        else:
            # 一旦发现之前抓过的,则彻底终止程序
            sys.exit('更新完成')

接下来就是提取一辆汽车的具体信息,并存入了Redis、MongoDB数据库

def get_one_car_info(self, href):
    """提取一辆汽车的具体信息"""
    two_url = 'https://www.che168.com' + href
    two_html = self.get_html(url=two_url)
    two_regex = '<div class="car-box">.*?<h3 class="car-brand-name">(.*?)</h3>.*?<ul class="brand-unit-item fn-clear">.*?<li>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<span.*?(?:"overlayPrice">|"price">)(.*?)(?:<b>|</span>)'
    # car_info_list:
    # [('宝马','12万公里','2004年','自动/2.5L','北京','4.20')]
    car_info_list = self.re_func(two_regex, two_html)
    item = {}
    item['name'] = car_info_list[0][0].strip()
    item['km'] = car_info_list[0][1].strip()
    item['time'] = car_info_list[0][2].strip()
    item['type'] = car_info_list[0][3].split('/')[0].strip()
    item['displace'] = car_info_list[0][3].split('/')[1].strip()
    item['address'] = car_info_list[0][4].strip()
    item['price'] = car_info_list[0][5].strip()

    print(item)
    # 数据存入到MongoDB数据库
    self.myset.insert_one(item)

最后程序入口函数,用来控制整体逻辑

 def run(self):
        for page in range(1, 5):
            page_url = self.url.format(page)
            self.parse_html(page_url)

if __name__ == '__main__':
    spider = CarSpider()
    spider.run()

我们先来看一下redis数据库有没有存入进去

先连接进去:redis-cli -h 你电脑的IP地址 -p 密码
然后:ping一下
能看到是pong就行

再:keys *
接着看到有这个car:spiders
输入:SMEMBERS car:spiders
就可以看到有很多数据了

在这里插入图片描述

注意:
我们再次运行代码的话不会再增加数据了,因为是redis我们避免了重复数据,所以,再次运行代码就会显示我们设置的这样:
在这里插入图片描述
而且再次查看redis数据库里页不会有新增的,可以自己看一下
mongodb数据的话自己看一下吧,因为这个不重要,不在本文中做详细介绍,可以看这篇关于mongodb的博客:

https://blog.csdn.net/Yxh666/article/details/111239743

最后奉上全部代码:

import requests
import re
import time
import random
from fake_useragent import UserAgent
import pymongo
import redis
from hashlib import md5
import sys

class CarSpider:
    def __init__(self):
        self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/'
        # mongodb的3个对象
        # 连接到mongodb
        self.conn = pymongo.MongoClient('localhost', 27017)
        self.db = self.conn['cardb']
        self.myset = self.db['carset']
        # 连接到redis
        self.r = redis.Redis(host='localhost', port=6379, db=0)

    def get_html(self, url):
        headers = {'User-Agent': UserAgent().random}
        # ignore参数: 解码时遇到不识别的字符直接忽略掉
        html = requests.get(url=url, headers=headers).content.decode('gb2312', 'ignore')

        return html

    def re_func(self, regex, html):
        pattern = re.compile(regex, re.S)
        r_list = pattern.findall(html)

        return r_list

    def md5_url(self, url):
        s = md5()
        s.update(url.encode())

        return s.hexdigest()

    def parse_html(self, one_url):
        one_html = self.get_html(url=one_url)
        one_regex = '<li class="cards-li list-photo-li".*?<a href="(.*?)".*?</li>'
        # href_list: ['/declear/xxx.html', '', '', '', ...]
        href_list = self.re_func(one_regex, one_html)
        for href in href_list:
            finger = self.md5_url(href)
            # 返回值1:之前没抓过
            if self.r.sadd('car:spiders', finger) == 1:
                # 拼接完整URL地址,发请求提取具体汽车信息
                self.get_one_car_info(href)
                time.sleep(random.randint(1, 2))
            else:
                # 一旦发现之前抓过的,则彻底终止程序
                sys.exit('更新完成')

    def get_one_car_info(self, href):
        two_url = 'https://www.che168.com' + href
        two_html = self.get_html(url=two_url)
        two_regex = '<div class="car-box">.*?<h3 class="car-brand-name">(.*?)</h3>.*?<ul class="brand-unit-item fn-clear">.*?<li>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<h4>(.*?)</h4>.*?<span.*?(?:"overlayPrice">|"price">)(.*?)(?:<b>|</span>)'
        # car_info_list:
        # [('宝马','12万公里','2004年','自动/2.5L','北京','4.20')]
        car_info_list = self.re_func(two_regex, two_html)
        item = {}
        item['name'] = car_info_list[0][0].strip()
        item['km'] = car_info_list[0][1].strip()
        item['time'] = car_info_list[0][2].strip()
        item['type'] = car_info_list[0][3].split('/')[0].strip()
        item['displace'] = car_info_list[0][3].split('/')[1].strip()
        item['address'] = car_info_list[0][4].strip()
        item['price'] = car_info_list[0][5].strip()

        print(item)
        # 数据存入到MongoDB数据库
        self.myset.insert_one(item)

    def run(self):
        for page in range(1, 5):
            page_url = self.url.format(page)
            self.parse_html(page_url)

if __name__ == '__main__':
    spider = CarSpider()
    spider.run()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨旭华 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值