全国做网站找哪家好/网址查询服务中心
今天我们实现增量爬虫~,先来了解一下啥是增量爬虫??
增量爬虫: 通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据
通俗来讲:就是当你在爬取一个网站的数据的时候,反反复复在爬取,比如现在有一个项目,需要你用爬虫爬取某网站的数据
但是这个爬虫不能每次都运行,都是从头到尾爬取数据吧,这也不利于高效率开发啊,而且,就算每次都爬取,那爬取的数据是不是有很多重合的
你昨天爬过一次,今天再爬,是不是昨天爬过的数据又是在重新爬取了?这样就会造成数据的冗余,所以就有了增量爬虫的到来
对他的定义我觉得就是懒爬取,因为就是我们在第一爬去数据的时候,爬取完毕后,再次启动爬虫程序,只要是那个网站没有跟新的数据,他就不会爬,一旦有了更新,他也只是爬取更新的数据,之前爬过的数据一律不再爬取,这样就节省了工作效率,更不会造成数据冗余
说了这么多,希望大家可以明白增量爬虫的意义所在,好了,我们接下来准备一下环境吧
项目环境
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、hashlibPython里面的hashlib模块提供了很多加密的算法,我们这次用hashlib的md5算法加密数据
5、requestspip install requests #安装requests是python实现的简单易用的HTTP库,使用起来比urllib简洁很多
好了,所需环境就这么多,就下来我们看一下怎么做了:
汽车之家二手车数据抓取
一、分析:1. 一级页面: 每辆汽车详情页的链接2. 二级页面: 每辆汽车具体的数据
二、建立自己的User-Agent池:2. from fake_useragent import UserAgentUserAgent().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']# 连接到redisself.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' + hreftwo_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 sysclass CarSpider:def __init__(self):self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/'# mongodb的3个对象# 连接到mongodbself.conn = pymongo.MongoClient('localhost', 27017)self.db = self.conn['cardb']self.myset = self.db['carset']# 连接到redisself.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 htmldef re_func(self, regex, html):pattern = re.compile(regex, re.S)r_list = pattern.findall(html)return r_listdef 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' + hreftwo_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()