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:\ProgramData\Microsoft\Windows\Start Menu\Programs

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()
posted on 2021-03-12 18:42  行之间  阅读(545)  评论(0编辑  收藏  举报