栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

srapy框架学习

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

srapy框架学习

一、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 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,statusresponse.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,自己添加或不用的话就设置Truebindaddress :输出绑定IPROBOTSTXT_OBEY:是否遵守协议LOG_FILE: 文件保存路径LOG_LEVEL:打印日志等级ERRORWARNINGINFOCONCURRENT_REQUESTS :开启线程数DOWNLOAD_DELAY:下载延迟DEFAULT_REQUEST_HEADERS:开启后覆盖默认的请求头下载中间件和爬虫中间件后面的参数越小,优先级越高管道中判断itemisinstance(item,经过的item类) scrapy基本用法 打印日志

引入依赖包import loggingscrapy中,如果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.RequestPOST请求: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要的是字典格式)


上面是直接从浏览器复制的,将字符串转换成字典

class DouyinxingtucookieDownloaderMiddleware:
    def process_request(self, request, spider):
        cookie = self.get_cookie()
        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
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/739265.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号