scrapy框架学习


一、IP代理池(比较简陋,后续更新)

验证ip,proxies用的是两个协议,http和https都要有

import re

import requests

url = 'https://tool.lu/ip'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62'
}
proxies ={
    'http':'47.243.190.108:7890',
    'https':'47.243.190.108:7890'
}
res = requests.get(url=url,headers=headers,proxies=proxies,timeout=3).text
ip = re.search(r'[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}',res,flags=re.S).group(0)
print(ip)

二、python爬虫之scrapy框架

先贴一张图 并来一个牛逼的连接Scrapy爬虫框架

在这里插入图片描述

基本命令

  • 生成基本框架
scrapy startproject myspider
  • 创建爬虫文件
cd myspider
scrapy genspider -t crawl SpiderName  DomaimName

ps:上面加的参数 -t crawl 是创建crawlspider,里面的Rule方法可以帮助提取url
例:笔趣阁,全站爬取

  • 首先,拿到更多的连接,然后,进入这个分类中,拿到分页的url,再然后,拿到每页的书籍url,并进入详情页
    在这里插入图片描述
  • 使用crawlspider,只需要三行就能拿到
    在这里插入图片描述
  • 解释一下上面的代码
  • LinkExtractor :提取器(就是提取页面url的,直接将页面url的规则放进去就行)
  • callback : 回调函数,就是提取页面内容,提取url是上面那个方法,这个就用在提取详情页(数据)的时候用
  • follow : 这么想,提取到的页面(page)的url,是不是还要再提取一边每个书籍的url,然后再提取详情页面数据,这个时候,就要加个follow=True
  • 运行
scrapy crawl SpiderName  
  • 运行后的数据就在在这里插入图片描述
  • 注意看,这个函数名是parse_item()
  • 如果是不加任何参数的框架,生成的函数时 parse()
scrapy stratproject myspider

response的一些返回值和参数

在这里插入图片描述

  • 返回值
  • 就是requests的返回参数,url,headers,status
  • response.body.decode() : 获取字节类型的相应内容
  • headers :请求头
  • response.text :获取字符串类型的响应内容
  • 参数
  • meta :这个参数主要用于传递item字典对象
  • callback:回调函数(有多页数据或有详情页)
  • dont_filter : 默认为False,去重
  • proxy : 设置代理,一般在item字典中
  • request.meta['proxy'] = 'https://' + 'ip:port'
  • setting中的配置
  • DOWNLOAD_TIMEOUT : 和request模块的timeout一样,设置超时
  • MAX_RETRY_TIMES : 最大请求次数(默认两次)
  • dont_retry : 请求失败的url不再请求
  • dont_merge_cookies : scrapy会自动保存返回的cookies,自己添加或不用的话就设置True
  • bindaddress :输出绑定IP
  • ROBOTSTXT_OBEY:是否遵守协议
  • LOG_FILE: 文件保存路径
  • LOG_LEVEL:打印日志等级
  • ERROR
  • WARNING
  • INFO
  • CONCURRENT_REQUESTS :开启线程数
  • DOWNLOAD_DELAY:下载延迟
  • DEFAULT_REQUEST_HEADERS:开启后覆盖默认的请求头
  • 下载中间件和爬虫中间件后面的参数越小,优先级越高
  • 管道中判断item
  • isinstance(item,经过的item类)

scrapy基本用法

打印日志

  • 引入依赖包
  • import logging
  • scrapy中,如果LOG_LEVEL指定了文件路径,那么就不会在控制台打印日志,会保存到log文件里
  • 这样打印的只是基本信息
  • 自定义添加日志,__name__是文件路径
  • logger = logging.getLogger(__name__)
  • logger.info('打印数据') 同样写入到日志文件里

设置run文件(setting同级)

import os
from scrapy import cmdline

cmdline.execute('scrapy crawl xt'.split())
# 或
os.system("scrapy crawl xt")

重写方法 start_requests

在这里插入图片描述

分为两个请求方式
  • GET请求:scrapy.Request
  • POST请求:scrapy.FormRequest
  • 不过我还是习惯用scrapy.Request,然后method=“POST”指定一下请求方式,其中data参数就写在body里(json格式)
  • 例:
yield scrapy.Request(url=self.start_urls[0],callback=self.parse_pages,method="POST",body=json.dumps(self.data), meta={'item': item})

更改中间件middlewares

随机UA代理

fake_useragent 是一个包,pip install一下

from fake_useragent import UserAgent
class DouyinxingtuUserAgentDownloaderMiddleware:
    def process_request(self, request, spider):
        agent = UserAgent(path='fake_useragent_0.1.11.json').random
        request.headers['User-Agent'] = agent
设置用户代理ip
class DouyinxingtuProxiesDownloaderMiddleware:
    def process_request(self, request, spider):
        porixList = getIp()
        self.porix = random.choice(porixList) # 116.208.24.72:8118
        request.meta['proxy'] ='https://'+self.porix
        print(request.meta)
    # 如果报错,就返回
    def process_exception(self, request, exception, spider):
        print('删除数据库的值')
        return request
设置cookie(scrapy中间件里设置cookie要的是字典格式)

在这里插入图片描述
上面是直接从浏览器复制的,将字符串转换成字典
selenium获取到的cookie看你怎么拼接的,字符串最后有没有空格什么的,反正scrapy用就要转字典

class DouyinxingtuCookieDownloaderMiddleware:
    def process_request(self, request, spider):
        cookie = self.get_cookie()
        # selenium获取到的
        cookies = dict([(l.split("=")[0], l.split("=")[-1]) for l in cookie.split(";")])
        # 从浏览器直接复制
        #cookies = dict([l.split("=", 1) for l in cookie.split("; ")])
        request.cookies=cookies

基于管道存储

先打开setting配置

这个是pipelines里面的类名
在这里插入图片描述

管道类配置
# mysql数据库存储
class DouyinxingtuPipelineMysqlSave:
    fp=None
    def open_spider(self,spider):
        print('爬虫开始')
        # 连接数据库

        pass

    def process_item(self,item,spider):
    	if isinstance(item,ChilijvxingItemDur):
            print('经过ChilijvxingItemDur')
        print(item) # 这个是items中的item
        pass

    def close_spider(self,spider):
        print('爬虫结束')
        pass
个人习惯,引入items中的类
  • 引入类,并赋值

    item = DouyinxingtuItem()
    item['data'] = response['data']
    
  • items
    在这里插入图片描述

保存数据库(mysql,原生sql)
连接数据库

引用setting中的变量要导入

from scrapy.utils.project import get_project_settings
setting = get_project_settings()
host = setting.get('MYSQL_HOST')
user = setting.get('MYSQL_USER')
pwd = setting.get('MYSQL_PASSWD')
db = setting.get('MYSQL_DB')
port = setting.get('MYSQL_PORT')
self.conn = pymysql.connect(host=host,user=user,password=pwd,db=db,port=port)
self.sousor = self.conn.cursor()
保存数据(原生sql)

执行sql语句

sql = ''
self.sousor.execute()
关闭数据库
self.sousor.close()
self.conn.commit()
self.conn.close()
在django项目里面创建scrapy
就能直接用ORM了
import os,django  # 导入依赖包
# 下面两行是引用项目的setting配置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Orm_Mysql.settings")# project_name 项目名称
django.setup()
# 导入model类
from app01.models import StarGov
然后就能直接用了
data = StarGov.objects.all()
print(data)
爬虫-数据解析
POST 请求
  • 一般是json格式,通过response.text得到str格式,json.loads()转字典
GET 请求
  • 大概率解析页面(html)
  • 可以直接通过xpath得到Selector类型的数据(类list),解析到的内容被封装在了Selector对象中
  • 这时候要调用extract()函数,从Selector中取出,
  • extract(). :整个取出 ,完整的列表
  • extract_first() : 取出第一个
出现乱码

在这里插入图片描述

使用通用编码方式
response.encode('iso-8859-1').decode('gbk')

在这里插入图片描述

scrapy-redis(搭建分布式)

相关配置

setting配置
  • REDIS_HOST:主机地址
  • REDIS_PORT:端口号
  • REDIS_PARAMS : 指定数据库和密码
  • SCHEDULER = “scrapy_redis.scheduler.Scheduler”
    • 使用scrapy-redis 组件自己的调度器(改变调度器存储位置)
  • DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter”
    • 确保所有的爬虫实例使用redis进行重复过滤
  • DUPEFILTER_PERSIST = True
    • 将Requests队列持久化到Redis,可支持暂停或重启爬虫(爬虫关闭后自动删除)
  • SCHEDULER_QUEUE_CLASS = ‘scrapy_redis.queue.PriorityQueue’
    • Requests的调度策略,默认优先级队列
  • 使用scrapy-redis封装好的管道
    • ITEM_PIPELINES = {
      ‘scrapy_redis.pipelines.RedisPipeline’: 300
      }

在这里插入图片描述

爬虫文件配置
  • 直接使用redis中存放的url,就不用在start_urls中固定写了
  • 引入,改变继承的父类
    • from scrapy_redis.spiders import RedisSpider

在这里插入图片描述

分布式中重写start_requests

能力有限,理解比较浅薄:就是scrapy-redis和scrapy相比,继承的父类不同,所以scrapy-redis不能用直接使用start-requests函数,看的教程都是重写make_requests_from_url方法

redis_key = "myspider:start_urls"
    def start_requests(self):
        for url in self.start_urls:
            yield self.make_requests_from_url(url=url)

    def make_requests_from_url(self, url):
        return Request(url=url,callback=self.parse,method='

在这里插入图片描述

解决 scrapy redis爬虫空跑

我是选择在setting同级目录添加exensions.py文件,setting添加相关配置

exension.py

内容,其实,这个监控还有很多用处,比如,链接为空了就将redis数据搬运到mongo/mysql

import redis
from scrapy import signals


class RedisSpiderClosedExensions(object):
    def __init__(self, crawler, host, port, db, pwd):
        self.crawler = crawler
        # 链接redis
        self.r = redis.Redis(host=host, port=port, db=db, password=pwd, decode_responses=True)

    @classmethod
    def from_crawler(cls, crawler):
        ext = cls(crawler,
                  # 获取redis参数
                  host=crawler.settings.get("REDIS_HOST"),
                  port=crawler.settings.get("REDIS_PORT"),
                  pwd=crawler.settings.get("REDIS_PARAMS")['password'],
                  db=crawler.settings.get("REDIS_PARAMS")['db']
                  )
        # 指定重写方法
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        crawler.signals.connect(ext.spider_idle, signal=signals.spider_idle)

        return ext

    def spider_opened(self, spider):
        spider.logger.info('-----spider开启-----')
        # print('-----spider开启-----')

    def spider_closed(self, spider):
        spider.logger.info('-----spider关闭-----')
        # print('-----spider关闭-----')

    def spider_idle(self, spider):
        # 获取队列的长度
        length = self.r.llen('myspider:start_urls')
        if length == 0:
            # 如果redis长度为0,则关闭该spider
            spider.logger.info('redis长度为0,关闭该spider')
            self.crawler.engine.close_spider(spider, 'closespider_pagecount')


setting.py

在这里插入图片描述

三、数据格式转换

unicode转中文

字符串.encode('utf-8').decode('unicode_escape') # python3

redis取出数据格式是bytes

连接数据库时加上参数

decode_responses=True

如果遇到bytes类型数据呢

直接使用data(str类型) = data(bytes类型).decode()

betmp = b'180.155.22.62'
temp = btemp.decode()

print(btemp)
print(type(temp))
print(temp)

在这里插入图片描述

前端base64数据加密

在获取页面ip的时候,遇到了这个document.write(window.atob(“MTgyLjIwNy4yMzIuMTM1”));

  • window.atob() 这个方法是将通过base64加密的数据还原
  • python中的解密方式是
    • btemp = base64.b64decode(data) # 数据类型bytes
      import base64
      input= 'TgwLjE1NS4yMi42Mg=='
      btemp = base64.b64decode(input)
      temp = btemp.decode()   # 转str类型数据
      

四、Django中嵌套scrapy

重要的是scrapy使用Django的orm

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'reptileProject.settings') # 导入django项目配置
django.setup() # 启动django

在scrapy项目里启动会找不到django项目

在这里插入图片描述
ps:先获取绝对路径,再cd过去 , 执行scrapy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

挚友灬

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

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

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

打赏作者

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

抵扣说明:

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

余额充值