ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

逆向爬虫18 Scrapy抓取全站数据和Redis入门

2022-02-05 20:02:59  阅读:261  来源: 互联网

标签:全站 18 resp redis 课件 key print Redis 数据


逆向爬虫18 Scrapy抓取全站数据和Redis入门

一、全站数据抓取

1. 什么是抓取全站数据?

我们曾经在过猪八戒,图片之家,BOSS直聘等网站,利用网站官方提供的搜索功能,搜索指定关键词的内容,并把这些内容都抓取下来。现在我们来总结一下这些网站信息的共同点。

1. 利用浏览器访问指定网站,并在官方的搜索栏中搜索想要的内容信息。
2. 服务器返回一系列页面列表,每个页面内包含着若干条被搜索内容的简介信息。
3. 逐条点击这些简介信息的网页链接就可以获得该条信息的详情内容。
4. 对服务器返回的每个页面列表均执行步骤3,直到页面列表全都遍历完成。

在这里插入图片描述

上图描述了全站数据抓取的基本模型,这个是个可以应用于很多网站,需求场景的通用模型,因此Scrapy专门针对这种情况专门写了一个全站数据抓取的案例,使我们只需要去关注简介信息,详情信息,页面列表翻页按钮这些每个网站不同的东西,而无需再编写这套通用的抓取数据业务逻辑的控制。总之,Scrapy想尽办法把通用的功能抽象出来只写一次,不通用的地方留出接口供用户自己实现。

本节使用汽车之家二手车页面来介绍如何进行全站数据抓取。

2. Scrapy传统的全站数据抓取

这部分内容之前做过,直接开干。

开始动手:

scrapy startproject qiche	# 创建汽车项目
cd qiche	# 进入qiche项目根目录
scrapy genspider ershouche che168.com	# 创建ershouche爬虫

代码说明:

ershouche.py文件

在这里插入图片描述

settings.py文件

在这里插入图片描述

源码展示:

ershouche.py源码
import scrapy
from scrapy.linkextractors import LinkExtractor

class ErshoucheSpider(scrapy.Spider):
    name = 'ershouche'
    allowed_domains = ['che168.com', 'autohome.com.cn']
    start_urls = ['https://www.che168.com/china/list/#pvareaid=110965']
    def parse(self, resp):
        print(resp.url)
        print(resp.xpath('//title/text()').extract_first().strip())   # 获取页面标题
        # hrefs = resp.xpath('//ul[@class="viewlist_ul"]/li/a/@href').extract()
        # for href in hrefs:
        #     # print(href)   # 打印下看看
        #     yield scrapy.Request(
        #         url=resp.urljoin(href),
        #         callback=self.parse_detail
        #     )
        # scrapy 还提供了链接提取器的东西,也可以帮我们提取到页面中的超链接
        le = LinkExtractor(restrict_xpaths=('//ul[@class="viewlist_ul"]/li/a',))
        links = le.extract_links(resp)  # 提取链接
        for link in links:
            # print(link)     # 打印下看看
            # print(link.text.replace(" ","").strip())    # 打印下看看
            # print(link.url)     # 打印下看看
            yield scrapy.Request(
                url=link.url,
                callback=self.parse_detail
            )
        # 开始分页
        page_le = LinkExtractor(restrict_xpaths=("//div[@id='listpagination']/a",))
        pages = page_le.extract_links(resp)
        for page in pages:
            yield scrapy.Request(
                url=page.url,   # 重复的url没关系. scrapy自动的帮我们完成去除重复
                # dont_filter=True,  # 不过滤 - 直接扔队列  别乱加
                callback=self.parse		# 下一页的内容和当前页一致. 然后数据解析的过程和当前页一致
            )

    def parse_detail(self, resp):
        try:
            print(resp.url)
            print(resp.xpath('//title/text()').extract_first().strip())   # 获取页面标题
        except Exception as e:
            # 有的是手机页面,不对
            print(resp.url)
            print("上面的URL报错了")

3. Scrapy CrawlSpider全站数据抓取

开始动手:

scrapy genspider -t ershou che168.com	# 创建ershou CrawlSpider爬虫

代码说明:

ershou.py文件

在这里插入图片描述

源码展示:

ershou.py源码
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

class ErshouSpider(CrawlSpider):    # CrawlSpider也继承了Spider,所以从根本上讲,ErshouSpider依然是一个Spider
    name = 'ershou'
    allowed_domains = ['che168.com', 'autohome.com.cn']
    start_urls = ['https://www.che168.com/china/list/#pvareaid=110965']

    rules = (   # rule 规则,这里定义了一堆规则,要求必须是元组或者列表
        # Rule: 规则对象
        Rule(LinkExtractor(restrict_xpaths=('//ul[@class="viewlist_ul"]/li/a')), callback='parse_item', follow=False),
        Rule(LinkExtractor(restrict_xpaths=("//div[@id='listpagination']/a")), follow=True),
    )

    # 这里不能自己写parse, parse由crawlSpider提供
    def parse_item(self, resp):
        # 处理页面详情
        if "topicm.che168.com" not in resp.url:
            try:
                title = resp.xpath("//h3[@class='car-brand-name']/text()").extract_first()
                price = resp.xpath("//span[@id='overlayPrice']/text()").extract_first()
                if not title:
                    title = resp.xpath("//h3[@class='car-brand-name']/i[@class='icon-cxc']/text()").extract_first()
                if not price:
                    price = resp.xpath("//div[@class='goodstartmoney']/text()").extract_first()
                title = title.replace(" ","").strip()
                price = price.replace(" ","").strip()
                print(title, price)
                with open("title_price.txt", mode="a", encoding="utf-8") as f:
                    f.write(f"{title},{price},{resp.url}\n")
            except Exception as e:
                print(f"{resp.url} 出错了")
                print(e)
                with open("error.txt", mode="a", encoding="utf-8") as f:
                    f.write(f"{resp.url} 出错了\n")
                    f.write(f"{e}\n")

4. 小结

使用Scrapy中的CrawlSpider模板可以帮我们快速的抓取全站数据,用起来很方便。

二、Redis简单使用

redis作为一款目前这个星球上性能最高的非关系型数据库之一。拥有每秒近十万次的读写能力,其实力只能用恐怖来形容。

1. 安装redis

redis是我见过这个星球上最好安装的软件了。比起前面的那一坨。它简直了…

直接把压缩包解压。然后配置一下环境变量就可以了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZVHKZDpf-1644061687934)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810184227132.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hmClu86N-1644061687935)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810184318301.png)]

接下来, 在环境变量中将该文件夹配置到path中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dcQdmVF7-1644061687935)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810184649037.png)]

我们给redis多配置几个东西(修改redis的配置文件, mac是: redis.conf, windows是: )

  1. 关闭bind

    # bind 127.0.0.1 ::1  # 注释掉它
    
  2. 关闭保护模式 windows不用设置

    protected-mode no    # 设置为no
    
  3. 设置密码

    requirepass 123456   # 设置密码
    

将redis怼到windows服务必须进入到redis目录后才可以

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwGphxxP-1644061687935)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810185306517.png)]

# 将redis安装到windows服务
redis-server.exe --service-install redis.windows.conf --loglevel verbose
# 卸载服务:
redis-server --service-uninstall
# 开启服务:
redis-server --service-start
# 停止服务:
redis-server --service-stop

使用redis-cli链接redis

redis-cli -h ip地址 -p 端口 --raw   # raw可以让redis显示出中文
auth 密码   # 如果有密码可以这样来登录, 如果没有.不用这一步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sqc9TNVh-1644061687936)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810185605290.png)]

附赠RDM, redis desktop manager。可以帮我们完成redis数据库的可视化操作(需要就装, 不需要就算)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ouFrRdKH-1644061687936)(C:\Users\Apphao\Downloads\IT学习\爬虫课件\樵夫老师第一期\腾讯课堂VIP爬虫课件\11_直播第十一天-CrawlSpider和redis\课件\image-20210810185659813.png)]

2. redis常见数据类型

redis中常见的数据类型有5个。

命令规则: 命令 key 参数

string

字符串(它自己认为是字符串, 我认为是任何东西。), redis最基础的数据类型。

常用命令

set key value  # 添加一条数据
get key		   # 查看一条数据
incr key       # 让该key对应的数据自增1(原子性, 安全)
incrby key count     # 让该key对应的value自增 count 
type key		# 查看数据类型(set进去的东西一律全是字符串)

例如

set name zhangsan  # 添加数据  name = zhangsan
get name		# 查看数据 zhangsan

set age 10
get age 	# 10
incr age	# 11
get age 	# 11
incrby age 5	# 16

hash

哈希, 相当于字典。

常见操作

hset key k1 v1   # 将k1, v1存储在key上
hget key k1      # 将key上的k1提取出来
hmset key k1 v1 k2 v2 k3 v3.... # 一次性将多个k,v存储在key
hmget key k1 k2....# 一次性将key中的k1, k2...提取出来
hgetall key 	# 一次性将key中所有内容全部提取
hkeys key		# 将key中所有的k全部提取
hvals key 		# 将key中所有的v全部提取

示例:

HMSET stu id 1 name sylar age 18
HMGET stu name age   # syalr 18
HGETALL stu		    # id 1 name sylar age 18
HKEYS stu 	# id name age
HVALS stu   # 1 syalr 18

list

列表, 底层是一个双向链表。可以从左边和右边进行插入。记住每次插入都要记得这货是个双向链表

常见操作

LPUSH key 数据1 数据2 数据3.... # 从左边插入数据
RPUSH key 数据1 数据2 数据3.... # 从右边插入数据
LRANGE key start stop     # 从start到stop提取数据. 

LLEN key	# 返回key对应列表的长度
LPOP key        # 从左边删除一个.并返回被删除元素
RPOP key		# 从右边删除一个.并返回被删除元素

示例:

LPUSH banji yiban erban sanban siban
LRANGE banji 0 -1   # yiban erban sanban siban
RPUSH ban ban1 ban2 ban3
LRANGE ban 0 -1     # ban1 ban2 ban3
LPOP ban  # ban1
LLEN key  # 2

set

set是无序的超大集合。无序, 不重复。

常见操作

SADD key 值   # 向集合内存入数据
SMEMBERS key  # 查看集合内所有元素
SCARD key # 查看key中元素的个数
SISMEMBER key val  # 查看key中是否包含val
SUNION key1 key2  # 并集
SDIFF key1 key2  # 差集合, 在key1中, 但不在key2中的数据
SINTER key1 key2 # 计算交集, 在key1和key2中都出现了的
SPOP key  # 随机从key中删除一个数据
SRANDMEMBER key count # 随机从key中查询count个数据

实例:

SADD stars 柯震东 吴亦凡 张默 房祖名   # 4
SADD stars 吴亦凡    # 0. 重复的数据是存储不进去的.
SMEMBERS stars   # 柯震东 吴亦凡 张默 房祖名
SISMEMBER stars 吴亦凡  # 吴亦凡在 stars里么?  1 在  0 不在

SADD my 周杰伦 吴亦凡 房祖名  
SINTER stars my  # 计算交集  吴亦凡 房祖名

SPOP my  # 随机删除一个
SRANDMEMEBER my 2   # 从集合总随机查看2个

zset

有序集合, 有序集合中的内容也是不可以重复的。并且存储的数据也是redis最基础的string数据。但是在存储数据的同时还增加了一个score。表示分值。redis就是通过这个score作为排序的规则的。

常用操作

ZADD key s1 m1 s2 m2 ... # 向key中存入 m1 m2 分数分别为s1 s2
ZRANGE key start stop [withscores]   # 查看从start 到stop中的所有数据 [是否要分数]
ZREVRANGE key start stop # 倒叙查看start到stop的数据
ZCARD key   # 查看zset的数据个数
ZCOUNT key min max  # 查看分数在min和max之间的数据量
ZINCRBY key score member  # 将key中member的分值score
ZSCORE key m  # 查看key中m的分值

示例:

ZADD fam 1 sylar 2 alex 3 tory  # 添加三个数据
ZRANGE fam 0 -1 WITHSCORES # 正序查看
ZREVRANGE fam 0 -1 WITHSCORES   # 倒叙查看
ZINCRBY fam 10 alex  # 给alex加10分
ZADD fam 100 alex   # 给alex修改分数为100分
ZSCORE fam alex   # 查看alex的分数
ZCARD fam    # 查看fam的数据个数

redis还有非常非常多的操作。我们就不一一列举了。各位可以在网络上找到非常多的资料。

各位大佬们注意。数据保存完一定要save一下, 避免数据没有写入硬盘而产生的数据丢失

3. python搞定redis

​ python处理redis使用专用的redis模块。同样的, 它也是一个第三方库.

pip install redis

​ 获取连接(1)

from redis import Redis

red = Redis(host="127.0.0.1",  # 地址
            port=6379,   # 端口
            db=0,   # 数据库
            password=123456,  # 密码
            decode_responses=True)  # 是否自动解码

​ 获取连接(2)

pool = redis.ConnectionPool(
        host="127.0.0.1",  # 地址
        port=6379,   # 端口
        db=0,   # 数据库
        password=123456,  # 密码
        decode_responses=True
)

r = redis.Redis(connection_pool=pool)
print(r.keys())

​ 我们以一个免费代理IP池能用到的操作来尝试一下redis

# 存入数据
red.set("sylar", "邱彦涛")
# 获取数据
print(red.get("sylar"))

lst = ["张三丰", "张无忌", "张翠山", "张娜拉"]
red.lpush("names", *lst)  # 将所有的名字都存入names

# # 查询所有数据
result = red.lrange("names", 0, -1)
print(result)

# 从上面的操作上可以看出. python中的redis和redis-cli中的操作是几乎一样的

# 接下来, 咱们站在一个代理IP池的角度来分析各个功能
# 抓取到了IP. 保存入库
red.zadd("proxy", {"192.168.1.1": 10, "192.168.1.2": 10})
red.zadd("proxy", {"192.168.1.3": 10, "192.168.1.6": 10})
red.zadd("proxy", {"192.168.1.4": 10, "192.168.1.7": 10})
red.zadd("proxy", {"192.168.1.5": 10, "192.168.1.8": 10})

# 给某一个ip增加到100分
red.zadd("proxy", {"192.168.1.4": 100})

# 给"192.168.1.4" 扣10分
red.zincrby("proxy", -10, "192.168.1.4")

# 分扣没了. 删除掉它
red.zrem("proxy", "192.168.1.4")

# 可用的代理数量
c = red.zcard("proxy")
print(c)
# 根据分值进行查询(0~100)之间
r = red.zrangebyscore("proxy", 0, 100)
print(r)

# 查询前100个数据(分页查询)
r = red.zrevrange('proxy', 0, 100)

# 判断proxy是否存在, 如果是None就是不存在
r = red.zscore("proxy", "192.168.1.4")
print(r)

标签:全站,18,resp,redis,课件,key,print,Redis,数据
来源: https://blog.csdn.net/weixin_40743639/article/details/122792696

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有