zoukankan      html  css  js  c++  java
  • python爬虫scrapy框架学习笔记2

    scrapy框架学习课程概要

    1.scrapy的基础概念
    2.scrapy的工作流程
    3.scrapy的入门使用
    4.scrapy的深入
    5.cralspider的使用

    为什么要学习scrapy?

    requests+selenium可以解决90%的需求
    scrapy不能解决剩下的10%的需求,但是它可以让爬虫更快,更强

    什么是scrapy?

    scrapy是一个为了爬取网站数据,提取结构性数据编写的应用框架,我们只需要实现少量的代码,就
    能够快速的抓取。它使用了Twisted异步网络框架,可以加快我们的下载速度。

    Scrapy Engine(引擎):总指挥,负责数据和信号在不同模块间的传递,scrapy已经实现;
    Scheduler(调度器):一个队列,存放引擎发过来的request请求,scrapy已经实现;
    Downloader(下载器):下载引擎发过来的requests请求,并返回给引擎,scrapy已经实现;
    Spider(爬虫):处理引擎发过来的response,提取数据,提取url,并交给引擎,需要手写;
    Item Pipeline(管道):处理引擎传过来的数据,比如存储,一般不用手写;
    Downloader Middlewares(下载中间件):可以自定义的下载扩展,比如设置代理,随机请求头,一般不用手写;
    Spider Middlewares(爬虫中间件):可以自定义requests请求和进行response过滤,一般不用手写;

    Scrapy入门

    0.安装scrapy

    pip install --index https://mirrors.ustc.edu.cn/pypi/web/simple/ scrapy

    1.创建一个scrapy项目

    scrapy startproject myspider

    2.生成一个爬虫

    scrapy genspider 爬虫名字 爬取的域名

    3.提取数据

    完善spider,使用xpath等方法

    4.保存数据pipeline中保存数据

    5.运行爬虫

    scrapy crawl 爬虫名字#带日志信息运行爬虫
    scrapy crawl 爬虫名字 --nolog#不带日志信息运行爬虫,也可以在settings.py中设置日志显示等级为LOG_LEVEL= “WARNING”
    ERROR : 一般错误;WARNING : 警告;INFO : 一般的信息;DEBUG : 调试信息;默认的显示级别是DEBUG

    若要处理数据,则需开启管道,在项目的settings.py文件中

    ITEM_PIPELINES = {
    'spider.pipelines.SpiderPipeline': 300,
    }
    键可以看作是管道类的路径,后面的值是有多个管道时,执行的顺序,值越小越优先执行

    
    class ItcastSpider(scrapy.Spider):
        name = 'itcast'#爬虫名字,可以用作不同管道处理的判断依据
        allowed_domains = ['itcast.cn']#允许爬取的域名范围
        start_urls = ['http://www.itcast.cn/channel/teacher.shtml']#最开始请求的url地址,对应响应到了parse方法
        
        """
        # 必须实现parse方法,否则会报下面的方法未实现错误,即parse名字不能改
        # 类似的在管道类中的process_item方法名也不能改 
        # NotImplementedError: ItcastSpider.parse callback is not defined
        # 数据提取方法,接收下载中间件传过来的response
        # 该方法专门处理start_urls[0]地址对应的响应.extract()
        """
        def parse(self, response):
            # res = response.xpath('//div[@class="tea_con"]//h3/text()')[1]
            # print(res)#返回包含Selector选择器的列表
            # [<Selector xpath='//div[@class="tea_con"]//h3/text()' data='黄老师'>,...]
            
            # 分组
            li_list = response.xpath('//div[@class="tea_con"]//li')
            
            for li in li_list:
                item = {}
                item['name'] = li.xpath('.//h3/text()').extract_first()
                item['title'] = li.xpath('.//h4/text()').extract_first()
                # 从选择器中提取字符串
                # 1.extract():返回一个包含有字符串数据的列表
                # 2.extract_first():返回列表中的第一个字符串
                
                yield item
                break
                """
                # 生成器,减少内存的占用,交给管道SpiderPipeline
                # Spider must return request, item, or None,所以不能添加到列表一并返回
                teachers = [];teachers.append(item);yield teachers
                """
    
    # 若要使用管道类,需要在settings.py文件中开启
    class SpiderPipeline:
        def process_item(self, item, spider):
            return item#return是为了数据能够在不同管道之间进行传递
    

    Windows DOS命令

    cd ..:回到上一级目录
    tree /f:以树形结构显示所有文件
    

    使用pipeline

    从pipeline的字典形式可以看出来,pipeline可以有多个,而且确实能够定义多个

    为什么需要多个pipeline?

    1.可能会有多个spider,不同的pipeline处理不同的item的内容;
    2.一个spider的内容可能要做不同的操作,比如存入不同数据库中;

    注意:
    1.pipeline的权重越小优先级越高;
    2.pipeline中process_item方法名不能修改为其他名称

    1.在scrapy框架中使用日志

    import logging
    logger = logging.getLogger(__name__)#当前运行文件的名字
    
    logger.warning('warning')
    
    在settings.py文件中设置
    # 设置日志级别,以及保存的文件,设置后终端不会显示日志信息
    LOG_LEVEL = 'WARNING'
    LOG_FILE= 'log.log'
    

    2.在普通程序中使用日志

    import logging
    
    # 设置日志输出样式
    logging.basicConfig(level=logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='%a, %d %b %Y %H:%M:%S',filename='log.log',filemode='a')
    logger = logging.getLogger(__name__)
    logger.warning('hello python')
    
    # Wed, 10 Mar 2021 18:37:24 日志学习.py[line:15] WARNING hello python
    

    如何实现翻页请求

    回忆:requests模块是如何发送翻页的请求的?
    1.找到下一页地址
    2.之后调用requests.get(url)

    scrapy思路
    1.找到下一页的地址
    2.构造一个关于下一页url地址的request请求传递给调度器

    抓包,分析响应中是否包含所需要的数据,若有,则可将对应的url作为起始url;若没有,则不能
    scrapy.Request(url, callback,meta,dont_filter=False)
    1.dont_filter:贴吧内容经常变换,此时需要将dont_filter置为True;
    2.callback:指定传入的url交给哪个解析函数去处理;
    3.meta:实现在不同的解析函数中传递数据,meta默认会携带部分信息,比如下载延迟,请求深度等;

    Scrapy深入之定义Item

    scrapy.Item也是一个字典,scrapy.Field()也是一个字典
    总之,我们可以把自己定义的MyspiderItem理解为一个字典
    那么scrapy吃饱了撑的为什么要定义一个字典类呢?
    大概原因有以下两点:
    1.在获取到数据的时候,使用不用的Item来存放不同的数据;
    2.在把数据交给pipeline的时候,可以同构isinstance(item, MyspiderItem)

    DEBUG信息的认识

    scrapy深入之scrapy shell

    scrapy shell是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试xpath表达式
    使用方法:scrapy shell http://www.itcast.cn/channel.teacher.shtml
    response的一些属性
    1.url:当前响应的url地址
    2.request.url:当前响应对应的请求的url地址
    3.headers:响应头
    4.body:响应体,也就是html代码,默认是byte类型
    5.text:html代码,str类型
    6.requests.headers:当前响应的请求头

    scrapy深入之认识setting.py文件

    为什么需要配置文件:
    1.配置文件存放一些公共的变量(比如数据库的地址,账号密码等)
    2.方便自己和别人修改
    3.一般用全大写字母命名变量名

    scrapy深入之pipeline使用

    def open_spider(self, spider):#在爬虫开启的时候执行,仅执行一次
    def close_spider(self, spider):#在爬虫关闭的时候执行,仅执行一次
    def process_item(self, item, spider):#
    	return item#不return的情况下,另一个权重较低的pipeline就不会获取到该item
    

    Mongodb回顾

    from pymongo import MongoClient
    
    def open_spider(self, spider):
    	client = MongoClient(spider.settings.get('HOST'), spider.settings.get(''PORT))
    	db = client[spider.settings.get('DB')]#连接到数据库
    	self.collection = db[spider.settings.get('COLLECTION')]#连接到集合
    
    def process_item(self, item, spider):
    	self.collection.insert(dict(item))#插入字典形式的item
    """
    mongodb shell命令回顾
    show dbs:查看数据库
    user books:使用数据库
    db.suning.find():无条件查找
    db.suning.find().pretty():查找并美化打印
    db.suning.remove({'category': '文学小说'}):删除所有category为文学小说的数据
    db.suning.drop():删除集合(表)
    """
    

    苏宁图书爬虫

    start_urls = 'https://book.suning.com/'

    如何确定一个地址能否成为start_urls地址,取决于url对应的响应中是否包含我们想要的数据;

    若有想要的数据,则可以成为start_urls地址,没有则不可以(大概率在ajax请求中)

    对比network抓包中的响应内容是否与浏览器渲染elments源码一样,一样则可依据elements进行提取

    from copy import deepcopy

    CrawlSpider的使用

    使用场景

    数据只在一个页面上,分页明显

    1.创建爬虫
    scrapy genspider -t crawl 爬虫名 allow_domain
    2.指定start_url:对应的响应会进入rules提取url地址
    3.使用正则,完善rules,添加Rule

    注意点:

    1.url地址不完整,crawlspider会自动补充完整之后再请求
    2.parse函数不能定义,他有特殊的功能需要实现
    3.callback参数:链接提取器提取出来的url对应的响应交给回调函数处理
    4.follow参数:链接提取器提取出来的url地址对应的响应是否继续被rules来过滤

    CrawlSpider补充了解

    LinkExtractor更多常见参数
    1.allow:满足括号中正则表达式的URL会被提取,如果为空,则全部匹配
    2.deny:满足括号中正则表达式的URL一定不提取(优先级高于allow)
    3.allow_domains:会被提取的链接的domains
    4.deny_domains:一定不会被提取链接的domains
    5.restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接,xpath满足范围内的url地址会被提取

    spiders.Rule常见参数

    1.link_extractor:是一个LinkExtractor对象,用于定义需要提取的链接
    2.callback:从link_extractor中每获取到连接时,参数所指定的值作为回调函数
    3.follow:是一个布尔值,指定列根据该规则从response提取的链接是否需要跟进;如果callback为None
    follow默认设置为True,否则默认为False
    4.process_links:指定该spider中哪个函数将会被调用,从link_extractor中获取到链接列表时将会调用
    该函数。该方法主要用来过滤url
    5.process_request:指定该spider中哪个的函数将会被调用,该规则提取到每个request时都会调用
    该函数。用来过滤request

    scrapy模拟登录

    为什么需要模拟登录?

    获取cookie,能够爬取登录后的页面;
    在之后的请求中带上获取到的cookie,就可以达到登录的效果

    回顾

    1.requests是如何模拟登录的?

    • 直接携带cookies请求页面
    • 找接口发送post请求存储cookie

    requests模拟登录三个方法

    • 1.使用session,先发post请求,对方服务器会在session中设置cookie,之后使用session发送后面的请求;
    • 2.把cookie字符串放到headers里面
    • 3.把cookie做成字典形式,放到request里面去,使用cookie参数接收

    2.selenium是如何模拟登录的?

    • 找到对应的input,用户名,密码标签,输入文字点击登录

    对于scrapy来说,有两个方法模拟登录

    1.直接携带cookie;
    2.找到发送post请求的地址,带上信息,发送请求。

    一、scrapy模拟登录之携带cookie

    应用场景

    1.cookie过期时间很长,常见于一些不规范的网站;
    2.能在cookie过期之前把所有的数据拿到
    3.配合其他程序使用,比如使用selenium把登录之后的cookie获取保存到本地,scrapy发送请求之前先读取本地cookie

    注意:如果程序只跑一遍,比较合适;但更多的时候是配合其他程序一起使用,如selenium

    携带cookie登录之前

    我们在spider下面定义了start_urls,那么这个start_urls是交给谁去处理的?
    查看源码,可以知道:我们定义的start_urls = []默认都是交给scrapy.Spider类start_requests处理的,
    所以如果必要,我们可以重写start_requests方法

    import scrapy
    import re
    
    class GitSpider(scrapy.Spider):
        name = 'git'
        allowed_domains = ['github.com']
        start_urls = ['https://github.com/feijiang-cloud']
        
        # 重写start_requests方法,模拟携带cookie登录
        def start_requests(self):
            # 先登录,拿到登录后的cookies字符串,使用字典推导式构造cookies字典
            cookies = '_ga=GA1.2.1210121656.1553845768; _octo=GH1.1.612568455.1553845769; _device_id=4fd174d4b3cb4f94f72bff21dbca9cf9; tz=Asia%2FShanghai; has_recent_activity=1; user_session=y3ej_ACURi0zLo7Xd9LEdrCtIVfgHlQkYd8Yz3J_MN5Fx5Mc; __Host-user_session_same_site=y3ej_ACURi0zLo7Xd9LEdrCtIVfgHlQkYd8Yz3J_MN5Fx5Mc; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22light%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=feijiang-cloud; _gh_sess=eHRZVh%2FdPfe2lESPdcjD2YS8ngYnxhkQxHpUcJS%2B1yqRcbnyBdU%2BdmcvQFTL7RP6gc%2BXkhpehaWXOzICqmlbr6wENmmRiQO%2FKQh%2B%2FqSvUzhIG7EoHsmigxCpQmkOs52mVDzOjAfkn%2FC8%2Bp5Nn3BttUyHKHT%2FJGnkHP4BFhvfk%2BgobQqjGC9g2%2BdMFqzw9vBm5h2JRhbzI3HJJXvy8fspXLV5nUas2hRXHn%2B62ncVBOFH8ALMx%2FAcwaOPpUw8eNCnOaWVIXS%2BMH4Vcnp%2FBPRhGS2rUYPc8vT3fiRHMirSKlXCiuSumfVitS9QBP5ABN5SpINl17E4p6CBuJpkmqpVepDGlsUS31qoFh%2BQA6FUNkV7uHXUNa9i8o4BM6aqelEPuY7nk3usOKj6o%2FwrlyNWv9WAdY02bHI%2FE0rLlziPC3RqN9jIiyQzl7dpLhxbfZP2o0uKxBTvm5QznUG7WJkBZ8wihieCu25M0ZXc%2F3emboAbhoymah7ZIuj2AdpYrhEjSKwI1RuRRRkSGazud%2FLBlaQuAkPGVSY3%2B1C9JtOGWejRFWQrboxbxORx52I3gIM6vO0DvZ3NyZz71rOtWM%2F%2BYiIhagoBt1hSjE0q%2BElFLfE6gA3q8%2BlnttGSU3v0vB52kCvUqekdtAiGe8fSjx%2B8XItyy198X3jdwAqzfLo1OX0%2F%2BO3%2Fiv6JJlzFJBrYDO3Af5GWx7ony7Qh%2FTfu5NvJdAkDK1phfu8yk52nQnvFN2ut70IBOofR0TXgzbJxiSeA2JaaHGkJ8%2BTxewbRkhBTWV5gfF356g0y1Ktzzi4jdMFhAT4ylbZsmHXERx0hKH4MICV4sxdRWgeMlYM1n3ww4lOyi4qBZNwvJ8L8zaiBbT5p8j4BkGmF3pD5nl%2FxB3YN%2Bi6KmZwlZg%2F9BUe%2Bp7nz9Hlxfn76mR32x%2BkPg4UTx%2BqHcvLyb1c4OBrEUo4BGo0l3swkPatKEEhVJQ8xRbahfI%2Bna0kL9mvcBdihezVWY5ptyF0nkLipp3q5A%2BGvF203BeW5maEXkF4ru0ZDI4ObNpccbHvSQJRpJeGr6nBJAkFB6HmARdZzsasLS52M7PJNmP%2FwOkP9MUh5kxk0NJAXzJEIkvLHd2vROd8TUSugrqi0HgFwgXDGmtY7PhtgreyueDAfoafXjjgXUmVfD9fj9HBaKWwGW%2FOxJiJEsGd573v0apsApp8Ca75CuJMhY8tVVZUFQZ7kOa6fgisMr%2F2AyJIUHCksgzDtw%2BJEsuviZ3zQTclB29g0mf%2BPXnwMQEL%2FNZ4%2BdW1lK%2B60Gq8QrZt%2Bsxh6iQcCQqQoNn%2FxhJ87BoAZZovNKRIrRT714sWXB4InitCIGGY17pNoWJHrt5jM78lkcpFc7WaZFeVqAIZ%2B%2FWNeTr%2BVmYQ67JE%2FOfbK6TPg--copajVr1PiKsDom0--tzPuxaystfXmhNiJvEXNsA%3D%3D'
            cookies = {data.split('=')[0]: data.split('=')[1] for data in cookies.split('; ')}
            
            yield scrapy.Request(url=self.start_urls[0], callback=self.parse, cookies=cookies)
            
        def parse(self, response):
            print(response.xpath('//head/title/text()').extract_first())
           
            val_str = re.findall('你需要找的字符串', response.body.decode())#response.text
            print('模拟登录失败') if val_str is None else print('模拟登录成功!')
    

    Tips:在settings.py文件中添加COOKIES_DUBUG = True,可以看到cookies的传递过程

    下载中间件

    使用方法

    编写一个Downloader Middlewares,和我们编写一个pipeline一样,定义一个类,然后在settings中开启
    Downloader Middleware默认的方法:
    1.process_request(self, request, spider):
    当每个request通过下载中间件时,该方法被调用
    2.process_response(self, request, response, spider):
    当下载器完成http请求,传递响应给引擎的时候调用
    Tips:自定义下载中间件的时候也需要在settings文件中开启
    下载中间件有两个作用:处理请求、处理响应

    下载中间件常用来做一些反爬的处理

    1添加随机请求头

    class RandomUserAgentMiddleware(object):
    	def process_request(self, request, spider):
    		user_agent - random.choice(USER_AGENT)
    		# user_agent = random.choice(spider.settings.get('USER_AGENT'))
    		request.headers['User-Agent'] = user_agent
    # 添加自定义的User-Agent,给request的headers赋值即可
    # 不能return request,如果return则又交给下载器,中间件就不起作用了
    

    2添加代理

    class ProxyMiddleware(object):
    	def process_request(self, request, spider):
    		request.meta['proxy'] = 'http://124.115.126.76:808'
    # 添加代理,需要在request的meta信息中添加proxy字段
    # 代理的形式为:协议+ip+端口
    # 有的需要密码,查看相关文档
    

    scrapy发送post请求(以登录为例)

    打开Preserve log,多次尝试,找出表单Form Data哪些字段是不变的,哪些是变的
    对于变的字段,可能来自的地方有很多
    1.可能在登录对应的响应里面
    2.当前响应里面
    3.也有可能是通过js生成的

    class Git2Spider(scrapy.Spider):
        name = 'git2'
        allowed_domains = ['github.com']
        start_urls = ['https://github.com/login']
    
        def parse(self, response):
            # 从登录页面响应中解析出post数据
            authenticity_token = response.xpath('//input[@name="authenticity_token"]/@value').extract_first()
            timestamp = response.xpath('//input[@name="timestamp"]/@value').extract_first()
            timestamp_secret = response.xpath('//input[@name="timestamp_secret"]/@value').extract_first()
            
            # 构造post表单数据
            post_data = {
                'commit': 'Sign in',
                'authenticity_token': authenticity_token,
                'login': 'feijiang-cloud',
                'password': 'j3JKv8pE0m',
                'trusted_device': '',
                'webauthn-support': 'supported',
                'webauthn-iuvpaa-support': 'unsupported',
                'return_to': '',
                'allow_signup': '',
                'client_id': '',
                'integration': '',
                'required_field_755d': '',
                'timestamp': timestamp,
                'timestamp_secret': timestamp_secret  
            }
            
            # 字典创建的另一种方式
            # form_data = dict(
            #     login = 'feijiang-cloud',
            #     password = 'j3JKv8pE0m',)
            
            print(post_data)
            # 针对登录表单url发送post请求
            yield scrapy.FormRequest(url='https://github.com/session', callback=self.after_login, formdata=post_data)
        
        def after_login(self, response):
            yield scrapy.Request('http://github.com/feijiang-cloud', callback=self.check_login)
        
        def check_login(self, response):
            """验证登录是否成功"""
            print(response.xpath('//head/title/text()').extract_first())
    

    scrapy.FormRequest.from_response()方法

    import re
    
    class Git3Spider(scrapy.Spider):
        name = 'git3'
        allowed_domains = ['github.com']
        start_urls = ['https://github.com/login']
    
        def parse(self, response):
            # 如果form表单有对应action地址,则可使用scrapy.FormRequest.from_response()方法
            # 发送请求,该方法自动从response中寻找form表单,并且把数据提交到form表单对应的action地址
            # formdata数据的键为input框对应的name,值为账号或密码
            yield scrapy.FormRequest.from_response(
                response, # 自动从该响应中寻找form表单进行登录
                formdata={'login':'feijiang-cloud', 'password':'j3JKv8pE0m'},
                callback=self.after_login
            )
            
        def after_login(self, response):
            """验证登录是否成功"""
            print(response.xpath('//head/title/text()').extract_first())
            print(re.findall('feijiang-cloud', response.body.decode()))
    

    总结和复习

    1.苏宁图书爬虫

    • 数据重复怎么办?
      原因:后一次循环的时候会改变前一次循环的结果,scrapy item同时被操作,而且使用的item来自同一个大分类
      解决方法:使用copy.deepcopy()
    • url地址为js生成怎么办?
      寻找url地址的规律;
      在响应中会有当前的页码数和总的页码数

    2.crawlspider

    • 如何使用?
      1)创建爬虫scrapy genspider -t crawl 爬虫名 allow_domain
      2)指定start_urls:根据响应中是否包含我们需要的数据,判断能否作为起始url
      3)完善rules:正则表达式;
      LinkExtractor:通过规则提取url地址;
      callback:链接提取器提取的url的响应会交给他处理;
      follow:链接提取器提取的url的响应会继续被rules提取url地址
      4)完善callback回调函数

    crawlspider的使用场景

    1.url的规律明显:能够通过正则或xpath表示
    2.最终的页面有全部的数据;如果没有,在callback中手动构造请求

    注意点

    1.parse函数不能定义
    2.继承自CrawlSpider

    3.下载中间件

    1.process_request

    • 处理请求
    • 添加随机请求头:request.headers['User-Agent'] = random.choice([])
    • 添加代理:request.meta['proxy'] = 'ip+port'
    • 不需要return request

    2.process_response

    • 处理响应
    • 需要return request,response

    4.模拟登录

    1.携带cookie登录:scrapy.Request(url, callback, cookies={})
    (使用字典生成式,不能把cookie放在headers中,无效)
    2.使用FormRequest:scrapy.FormRequest(url, formdata={},callback)
    (formdata:请求体)
    3.自动寻找form表单中的action的url:
    scrapy.FormRequest.from_response(response, formdata={}, callback)

    使用scrapy框架,遇到返回的响应,需要的数据是被注释掉的怎么办?

    text = response.text.replace('<code', '').replace('<!--', '')
    response = scrapy.Selector(text=text)

    .get()与.extract_first()方法效果一样

    什么是scrapy_redis

    基于redis的一个scrapy组件,scrapy能够快速帮助我们抓取数据,
    scrapy_redis在scrapy的基础上实现了更多,更强大的功能,具体体现在:
    request去重,爬虫持久化和轻松实现分布式

    redis是什么?

    Redis是一个开源的,内存数据库,它可以用作数据库,缓存和消息中间件。
    它支持多种类型的数据结构,如字符串,哈希,列表,集合,有序集合等

    大文件下载(图片)

    url = 'http://www.521609.com/daxuexiaohua/'
    
    import scrapy
    from scrapy.pipelines.images import ImagesPipeline# 提供了数据下载功能
    from scrapy.pipelines.media import MediaPipeline
    from scrapy.pipelines.files import FilesPipeline
    
    # 默认管道无法帮助我们请求到图片数据,因此该管道我们就不用了
    # 管道需要接收item中的图片名称和地址,再进行图片的持久化存储
    # class XiaohuaPipeline:
    #     def process_item(self, item, spider):
    #         return item
    
    # 自定义管道类,并在settings.py文件中注册
    class ImagePipeline(ImagesPipeline):
        # 根据图片地址发起请求
        def get_media_requests(self, item, info):
            yield scrapy.Request(url=item['src'], meta={'item':item})
    
        def file_path(self, request, response=None, info=None):
            item = request.meta['item']#通过request获取meta参数
            savename = item['name'] + '.jpg'
            print(savename)
            return savename#只需要返回图片名称
        # 在settings.py文件中设置图片保存路径,没有则自动创建:IMAGES_STORE = './images'
        
        # 将item传递给下一个即将被执行的管道类,若没有下一管道类,则可有可无
        def item_completed(self, results, item, info):
            return item
    

    大文件下载

    1.下属管道类是scrapy封装好的,我们直接用即可
    2.from scrapy.pipelines.images import ImagesPipeline
    - 提供了数据下载功能
    - 重写三个方法
    - get_media_requests:对图片发起请求
    - file_path:返回图片名称即可
    - item_completed:返回item,将其返回给下一个即将被执行的管道类
    - 在配置文件中添加配置:IMAGES_STORE = 'folder_name'

    settings.py中的常用配置

    1.增加并发:CONCURRENT_REQUESTS = 32
    2.降低日志级别: LOG_LEVEL = 'DEBUG'
    3.禁止cookie: COOKIES_ENABLED = FALSE
    4.禁止重试: RETRY_ENABLED = FALSE
    5.减少下载超时: DOWNLOAD_TIMEOUT = 10

    暴走白嫖收费文档

    1.文字处右键,选择检查,展开节点复制
    2.浏览器开发者工具,console,输入$=0,自由复制(亲测好像无效)
    3.Ctrl+p调出打印界面,自由复制(复制百度文库失败)
    4.使用谷歌插件和xpath表达式,相当专业
    5.借助工具下载并生成pdf,如冰点,用浏览器打开,自由复制
    6.截图,图片转文字

    电脑开始菜单文件位置

    C:ProgramDataMicrosoftWindowsStart MenuPrograms

    selenium隐式等待使用方式

    from selenium import webdriver
    
    def get_qqmusic_href():
        url = 'https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E9%80%81%E4%BD%A0%E4%B8%80%E6%9C%B5%E5%B0%8F%E7%BA%A2%E8%8A%B1'
        driver = webdriver.Chrome()
        driver.get(url)
        # 代码的运行速度要比浏览器加载速度快
        # 如果我进入网页,数据没有加载出来,不能获取到数据
        # 可以使用time.sleep(3)强制等待
        
        # 但是selenium有一个更智能的隐式等待
        # 3s之内元素加载完成即可,即此时的3s代表最长等待时间
        driver.implicitly_wait(3)
        # .get_attribute('href'):获取a标签的href属性,selenium语法和xpath语法不一样
        href = driver.find_element_by_xpath('//span[@class="songlist__songname_txt"]/a').get_attribute('href')
        return href
    

    网易云歌曲下载链接

    url = 'https://music.163.com/song/media/outer/url?id='+对应的歌曲id
    douqq.com/qqmusic/

    谷歌DevTools调试工具的使用技巧

    1.Elements:

    • 可以看到整个页面的结构,所有的DOM节点;以及外链的js、css文件。
    • 选中元素之后出现的Computed:相当于js的getComputedStyle返回的内容
    • Event Listeners:可查看对应元素绑定的事件

    2.Console:

    • 你输出的error、warning、info和debug会显示在那里
    • 可以直接在那里写js代码,用来测试你封装的函数对不对等等

    3.Sources:

    • 在这里可以看到网页的所有资源
    • 也可以在此进行js调试,点击行号即可打断点,好处是可以看到前面所有元素的值

    4.Network:

    • 点击All可以查看到网页的所有请求
    • Preserve log:表示不要清空上一次请求的记录
    • Disable cache:让请求不走cache,也就是不会出现304的状态码,成功状态码是200
    • XHR:XML HttpRequest,调的服务端接口请求都在这里,header可以看到详细信息
      • Cookies:本次请求携带的cookie
      • Timing:本次请求花费的时间
    • No t和rottling、Fast 3G、Slow 3G等表示不同网络下的效果,比如切换为3G,加载就会变慢

    5.Performance:

    • 性能检测
    • 通过分析生成的报表,能知道页面的性能瓶颈,从而找到相应的方法去优化
    • 尤其是首屏加载,想要秒开的话,就要详细分析这里的内容

    6.Memory:

    7.Application

    8.Security:

    9.Audits:

    电商网站对于商品的价格的保护是非常严格的

    比如要滑动滚动条的时候,下面的商品价格才会出现
    这是常见的反爬手段,例如拉动滚动条去发送请求,再重新渲染
    所以在用selenium打开网页后,还要让他模拟一下正常用户的行为
    执行下拉滚动条到浏览器下端的操作

    driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
    # 获取完加载数据后的网页源码
    time.sleep(3)
    page_source= driver.page_source
    拿到动态数据,用静态手段提取
    html = etree.HTML(page_source)
    翻页
    next_page = driver.find_element_by_xpath('/a[text()="下一页"]')
    # 模拟点击
    next_page.click()
    data_dic = {}
    df = pd.DataFrame(data_dic)
    df.to_excel('data.xlsx', index=False)
    
    # 退出当前页面,并且关闭浏览器
    driver.close()
    driver.quit()
    
  • 相关阅读:
    java encoding
    [转]shell 变量的作用域
    [转] shell :解析json的命令-jq
    [转] Linux user-space Atomic Operations && GCC Atomic builtins
    [转]reference counting
    [转]memory order,memory barrier,原子操作
    [转]c语言volatile 关键字
    OCF介绍
    [转]计算机存储 cache介绍
    [转] linux IO
  • 原文地址:https://www.cnblogs.com/zxfei/p/14525814.html
Copyright © 2011-2022 走看看