爬虫笔记...

scrapy运行流程
先弄清除他的运行流程之外,得先知道他的5大核心组件
1 spider,爬虫
2 引擎
3 调度器
4 下载器
5 管道

流程:
- 在爬虫类中定义要爬取得url,将url封装成一个对象,传入引擎
- 引擎接收到对象,将对象传到调度器
- 调度器由2个部分组成,一个是过滤器,一个是队列,每一个url对象都会经过过滤器去重,然后存在队列中,将队列传给引擎
- 引擎接收到队列,将队列给到下载器
- 下载器接到队列,在互联网中下载资源,下好得资源得到一个response,将response传递给引擎
- 引擎将response传递给爬虫得parse方法,解析response,然后封装item,将item传递给管道进行持久化存储

问题:
为什么都要经过引擎?
    - 因为引擎可以触发事务
    - Scrapy引擎是整个框架的核心。它用来控制调试器、下载器、爬虫。实际上,引擎相当于计算机的CPU,它控制着整个流程。

在爬虫和引擎之间 下载器和引擎之间都有个中间件
    - 下载器和引擎之间得中间件可以做ip池和UA池

创建项目
- scrapy startproject namepro
- cd namepro
- scrapy genspider name www.xxx.com

启动项目
- scrapy crawl name

settings需要配置
- 开启管道
- 可以开启多个管道,连着一起用,需要的是优先执行问题
- 传递给管道得值 yield item item 必须是Request, BaseItem, dict, None 其他报错
- 爬虫中间件,下载中间件,都需要开启

pipeline使用
- 为什么需要多个pipeline,可能有多个spider,不同的pipeline处理不同的item的内容
- pipeline的权重越小,优先级越大
- process_item不能改名
- spider参数 spider.name 返回项目名字

logging模块
- LOG_LEVEL = 'ERROR'
- LOG_FILE = './log.log'

构造请求 翻页

传参数
yield scrapy.Request(url='xx',rollback=self.parse,meta={'item':item})
    item = response.meta.get('item')
    item['x'] = x
    yield item

DEBUG:
pass

scrapy shell
使用方法: scrapy shell url地址 进入类似python终端界面
可以调试 response.xxx 之类

管道 -> 数据保存
- open_spider(self,spider) 爬虫开启执行 -> 数据库建立连接 仅执行一次
- process_item(self,item,spider) 处理Item -> 存入数据库
- close_spider(self,spider) 爬虫结束 -> 数据库关闭连接 执行一次
- from_crawler(self,crawler)

全站爬取 crawlspider
- scrapy startproject xxpro
- scrapy genspider -t crawl xx www.xx.com

# 定义提取规则地方
rules = (
    # LinkExtractor 连接提取器,提取url地址
    # callback 提取出来的response给callback处理, 可以不写
    # follow 当前url地址的响应是否重新经过rules来提取url地址
    Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
)

- crawlspider里面不能定义parse方法
- 如果多个rule都满足一个url,会选择第一个进行操作

scrapy携带cookie模拟登录
- 先去找起始url的首页,不需要cookie登录的那种,
- 获取他的cookie,再去请求需要cookie的网页

下载中间件的使用
- DownloaderMiddlewares:
process_request(self,request,spider):
当每个request请求通过下载中间件的时候,该方法调用, UA伪造,代理
request.headers['User-Agent'] = 'ua'
request.meta['proxy'] = '代理' https / http 看爬取的网站是什么

    process_response(self,request,response,spider):
        当下载器完成http请求,传递响应给引擎的时候调用
        return response

    process_exception(request,exception,spider)
        出错时调用

scrapy发送post请求
scrapy.FormRequest(url,formdata,callback)

scrapy.FormRequest.from_response(response,formdata={user,pwd},callback)  # 简单
                                # input用户名 name的值作为键 fromid formname 定位form表单

问题
数据重复怎么办
- 后一次循坏会改变前一次的结果,item同时会被操作,而且使用的item来之同一个
- 使用深copy复制item
url地址js生成怎么办
- 寻找规律
- 在响应中会有当前页码数和总的页码数
crawlspider
- 如何使用
1 scrapy startproject namepro
2 scrapy genspider -t crawl name
3 完善rules 一个元组 一个Rule linkExtractor callback follow
4 完善callback
- 使用场景
1 url的规则能够通过正则或者xpath
2 最终页面有全部数据的时候使用,如果没有,在callback中手动构造请求
-注意点
1 parse函数不能定义
2 继承自CrawlSpider
下载中间件
process_request()
处理请求
添加cookie
添加ua request.headers['u-a']
添加代理 request.meta['proxy']
不需要return
process_response()
处理响应
需要 return response

模拟登录
    - 携带cookie登录
        scrapy.request(url,callback,cookies={})
        不能吧cookies放在headers中
    - 使用FormRequest
        scrapy.FormRequest(url,formdata={},callback) formdata 请求体
    - 自动寻找form表单中的action的url
        scrapy.FormRequest.form_response(response,formdata={},callback)  formdata 用户名,密码

补充url地址
urllib.parse.urljoin(response.url, item['url'])

response的常见属性.
url
status_code
request.headers 响应对象对应的请求头
headers
request._cookies
request.cookies 答应响应的中的cookies
json()

request
get params
post data

在headers携带cookie  header = {'Cookie':'xx'}

timeout 参数使用  timeout=3  3s不响应报错

proxies = {'https':'https://127.0.0.1:8080'}

verify参数忽略CA证书      verify=False

post数据来源
    1.固定值            抓包不变值
    2.输入值            抓包笔记根据自身变化
    3.预设值-静态文件中  需要提前从静态文件获取 re
    4.预设值-发请求      需要对指定地址发送请求获取数据
    5.在客户端生成       分析js文件,模拟生成数据

session使用方法  保持会话  多次连续的请求
    session = requests.session() 实例化
    response = session.get(url,headers)
    response = session.post(url,headers)

数据提取
jsonpath 多层嵌套的复杂字典直接提取
from jsonpath import jsonpath
ret = jsonpath(a,'语法') $根节点 .直接子节点 ..内部任意位置

lxml模块  xpath
/ // name  text()  ..父节点 .当前节点 @ 选取属性  *通配任意一个节点

//title/[@lang="eng"]  选取lang属性值为eng的title标签
/div[last()-1]  选取最后第二个div标签
/div[text()='导演']  选取div文本为导演的标签
/h1/div[price>20]/title  选取h1标签下div的price价格大于20的title标签
1.通过索引来选择节点   [1]
2.通过属性值来选择节点 [@class="xx"]
3.通过子节点的值来选择节点  //span[ul>200]   //div[span[2]>200]
4.通过包含修饰            //div[contains(@id,'xxx')]   //div[contains(text(),'下一页')]

找翻页url 不用使用索引

浏览器进入内容被注释的解决方法
换个请求UA low的
response.decode().replace("",'') 替换掉

scrapy框架中
response.url 当前响应url
response.request.url 当前响应对应的url
response.headers 响应头 对面url的
response.request.headers当前响应的请求头 我方的
response.body 响应体,bytes类型
response.status 状态
response.urljoin 拼接url

保存数据  pipelines.py  对数据进行操作  process_item
在setting.py里面进行开启管道操作

数据建模 Items.py  里面确定目标
开发流程:
1 创建项目
2 明确目标
3 创建爬虫
4 保存数据

翻页请求如何处理
1 找到下一页的url
2 构造请求 scrapy.Request(url,callback,meta)

scrapy.Request() 更多参数
callback 指定回调函数
meta  参数传递      有一个固定的键 proxy 表示代理
method 指定post get请求
headers 接受一个字典,不包括cookie
cookies 接受一个字典,专门放cookie
body    接受json字符串,为post数据
dont_filter 设置过滤


scrapy模拟登录
    cookies参数
    模拟登录
    start_requests 重写  在这个方法得到一个cookie的字典 得到这个cookie在去重新请求url
    yield scrapy.Request(url=url,callback=self.parse,cookies=cookie)

scrapy.FormRequest()  能够发送post请求,和ajax请求  url,formdata,callback
    cookie = response.headers.getlist('Set-Cookie')

scrapy 管道的使用
    process_item(self,item,spider) 对数据item处理 必须return item
    在settings中能够开启多个管道,为什么需要开启多个
        - 不同的pipeline可以处理不同的爬虫的数据,通过spider.name来区分
        - 不同的pipeline能够对一个或多个进行不同的数据处理的操作,比如一个数据清洗,数据保存
        - 同一个也可以处理不同爬虫的数据,通过spider.name来区分

crawlspider
    - 继承Spider类
    - 自动根据规则链接并且发送给引擎

scrapy中间件的使用  预处理请求对象和响应对象
    - 对header以及cookie进行更换和处理
    - 使用代理ip等
    - 对请求进行定制化操作

Downloader_Middlewares下载中间件
    process_request
    当每个request通过下载中间件时,该方法进行调用
        None     如果所有的下载中间件都返回None,则请求最终被交给下载器处理
        request  如果返回请求,则将请求返回给调度器
        response 将响应对象返回给spider,进行解析

    process_response
    当下载器完成http请求,传递响应给引擎的时候调度
        request  如果返回请求,则将请求返回给调度器
        response 将响应对象返回给spider,进行解析
1 在middleware.py定义中间件方法
2 在中间件类中,重写处理或者响应方法
3 在setting中开启中间件的使用

代理ip使用
- 代理添加的位置: request.meta增加proxy字段
- 获取一个代理ip,赋值给 request.meta['proxy']     ip:port
    代理池中随机选择ip
    代理ip的weiapi发送请求获取一个ip

中间件使用selenium
    见scrapy_middle UApro
posted @ 2020-10-12 21:18  李淳罡zZ  阅读(84)  评论(0)    收藏  举报