爬虫学习笔记04-分布式与协程

news/2024/7/19 12:19:00 标签: 爬虫, 学习, 笔记, 算法, python

爬虫学习笔记04-分布式与协程

分布式

我们需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取,提升爬取数据的效率。

如何实现分布式?

安装一个scrapy-redis的组件。原生的scarapy是不可以实现分布式爬虫的,我们必须要让scrapy结合着scarapy-redis组件一起实现分布式爬虫

为什么原生的scrapy不可以实现分布式?

调度器不可以被分布机群共享
管道不可以被分布式机群共享

scrapy-redis组件作用

-可以给原生的scrapy框架提供可以被共享的管道和调度器

实现流程

创建一个工程
创建一个基于CrawlSpider的爬虫文件
修改当前的爬虫文件:
-导包:from scrapy_redis.spider import RedisCrawlSpider
-将start_urls和allowed_domains进行注释
-添加一个新属性:redis_key='sun’可以被共享的调度器队列的名称
-编写数据解析相关的操作
-将当前爬虫类的父类修改成RedisCrawlSpider
-修改配置文件settings:
-指定使用可以被共享的管道:

python">ITEM_PIPELINES={
		'scrapy_redis.pipelines.RedisPipeline':400
} 

​ -指定调度器

python">#增加了一个去重容器类的配置,作用使用Redis的set集合来储存请求的指纹数据,从而实现请求去重的持久化存储
DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'
#使用scrapy-redis组件自己的调度器
SCHEDULER='scrapy_redis.scheduler.Scheduler'
#配置调度器是否要持久化,也就是当爬虫结束了,要不要清空Redis中请求队列和去重指纹的set。
SCHEDULER_PERSIST=True

-redis相关操作配置:
-配置redis的配置文件:
-linux或者mac:redis.conf
-windows:redis.windows.conf
-打开配置文件修改:
①将bind 127.0.0.0进行注释
②关闭保护模式:protected-mode yes改为no
-结合着配置文件启动redis服务
-redis-server 配置文件
-启动客户端:
-redis-cli
-执行工程:
-scrapy runspider xxx.py
-向调度器的队列放入一个起始的url:
-调度器的队列在redis的客户端中
-lpush xxx www.xxx.com
-爬取到的数据存储在了redis的proName:items这个数据结构中

实战代码

python">from selenium import webdriver
from time import sleep
from lxml import etree
#实例化一个浏览器对象(传入浏览器的驱动程序)
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
#让浏览器发起一个指定url对应请求
bro.get("http://scxk.nmpa.gov.cn:81/xk/")
#page_sourse获取浏览器当前页面的页面源码数据
page_text=bro.page_source
#解析企业名称
tree=etree.HTML(page_text)
li_list=tree.xpath('//*[@id="gzlist"]/li')
for li in li_list:
    name=li.xpath('./dl/@title')[0]
    print(name)
sleep(5)
bro.quit()
python">from selenium import webdriver
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://www.taobao.com')
#标签定位
search_input=bro.find_element_by_id('q')
#标签交互
search_input.send_keys('Iphone')
#执行一组js程序
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
#点击搜索按钮
btn=bro.find_element_by_css_selector('.btn-search')
btn.click()
bro.get('https://www.baidu.com')
sleep(2)
#回退
bro.back()
sleep(2)
bro.forward()
sleep(5)
bro.quit()
python">#selenium
from selenium import webdriver
from time import sleep
#导入动作链对应的类
from selenium.webdriver import ActionChains
bro =webdriver.Chrome(executable_path='./chromedriver')
bro.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
#如果定位的标签是存在于iframe标签之中的则必须通过如下操作再进行标签定位
bro.switch_to.frame('iframeResult')#切换浏览器标签定位的作用域
div=bro.find_element_by_id('draggable')
#动作链
action=ActionChains(bro)
#点击长按指定的标签
action.click_and_hold(div)
for i in range(5):
    #perform()立即执行动作链操作
    #move by offset(x,y):x表示水平方向,y表示竖直方向
    action.move_by_offset(17,0).perform()
    sleep(0.3)
#释放动作链
action.release()
print(div)
bro.quit()

python">#需求:模拟登陆QQ空间
from selenium import webdriver
from time import sleep

bro=webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://qzone.qq.com/')
bro.switch_to_frame('login_frame')
a_tag=bro.find_element_by_id('switcher_plogin')
a_tag.click()
userName_tag=bro.find_element_by_id('u')
password_tag=bro.find_element_by_id('p')
sleep(1)
userName_tag.send_keys('1264532114')
sleep(1)
password_tag.send_keys('123456789')
btn=bro.find_element_by_id('login_button')
sleep(1)
btn.click()
sleep(3)
bro.quit()
python">#需求:实现selenium规避检测
from selenium import webdriver
from time import sleep
from selenium.webdriver import ChromeOptions  #实现规避检测
from selenium.webdriver.chrome.options import Options #实现无可视化界面
#实现无可视化界面的操作
chrome_options=Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
#实现规避检测
option=ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

#如何实现让selenium规避被检测到的风险
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
#无可视化界面(无头浏览器) phantomJS
bro.get('https://www.baidu.com')
print(bro.page_source)
sleep(2)
bro.quit()

协程

协程(coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。

实现协程的方式

-greenlet,早期模块
-yield关键字
-asyncio装饰器(py3.4)
-async、await关键字(py3.5)【推荐】

grenlet实现协程
环境安装

pip3 install greenlet

python">from greenlet import greenlet
def func1():
	print(1)  #第一步输出1
	gr2.switch()#切换到func2函数
	print(2)#输出2
	gr2.switch()#切换到func2函数,从上一次执行的位置继续向后执行
def func2():
	print(3)
	gr1.switch()
	print(4)
gr1=greenlet(func1)
gr2=grrenlet(func2)
gr1.switch()#去执行func1函数

#输出:1324
yield关键字
python">def func1():
	yield 1
	yield from func2()
	yield 2
def func2():
	yield 3
	yield 4
f1=func1()
for item in f1:
	print(item)
asyncio

python3.4以及之后的版本可以使用。

python">import asyncio 
@asyncio.coroutine
def func1():
	print(1)
	yield from asyncio.sleep(2)#遇到IO耗时操作,自动化切换到tasks中的其他任务
	print(2)

@asyncio.coroutine
def func2():
	print(3)
	yield from asyncio.sleep(2) #遇到IO耗时操作,自动化切换到tasks的其他任务
	print(4)

tasks=[
	asyncio.ensure_future(func1()),
	asyncio.ensure_future(func2())
]
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
async&await关键字

python3.5及以后的版本可以使用

python">import asyncio 
async def func1():
	print(1)
	await asyncio.sleep(2)
	print(2)
	
async def func2():
	print(3)
	await asyncio.sleep(2)
	print(4)
	
tasks=[
	asyncio.ensure_future(func1()),
	asyncio.ensure_future(func2())
]
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
协程的意义

在一个线程中如果遇到IO等待时间,线程不会傻傻等,利用空闲的时候再去干点其他事。
案例:去下载三张图片(网络IO)。

·普通方式(同步)

python">import requests
def download_image(url):
    print("开始下载",url)
    #发送网络请求
    response=requests.get(url)
    print('下载完成')
    #图片保存到本地文件
    file_name=url.rsplit('_')[-1]
    with open(file_name,mode='wb') as file_object:
        file_object.write(response.content)


if __name__=='__main__':
    url_list=[
        'https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif',
    ]
    for item in url_list:
        download_image(item)

异步协程
python">#下载图片使用第三方模块aiohttp,请提前安装:
#pip3 install aiohttp
import aiohttp
import asyncio

async def fetch(session,url):
    print("发送请求",url)
    async  with session.get|(url,verify_ssl=False) as response:
        content=await  response.content.read()
        file_name=url.rsplit('_')[-1]
        with open(file_name,mode='wb') as file_object:
            file_object.write(content)
    print('下载完成',url)

async def main():
    async with aiohttp.ClientSession() as session:
        url_list=[
            'https://www.baidu.com/img/dong_8f1d47bcb77d74a1e029d8cbb3b33854.gif',
        ]
    tasks=[asyncio.create_task(fetch(session,url)) for url in url_list]
    await asyncio.wait(tasks)


if __name__=='__main__':
    asyncio.run(main())

http://www.niftyadmin.cn/n/403861.html

相关文章

11.Linux使用vi编辑器编译文本

要使用 vi 编辑器编辑文本,可以按照以下步骤操作: 打开终端或命令行界面。输入命令 vi 文件名(例如 vi test.txt)打开该文件。如果文件不存在,则会创建一个新的空文件。进入命令模式:按下 Esc 键。在命令模…

Web3.0概念

学习web3您需要先掌握 JavaScript node React 后续 我们将学习一门新的语言 叫 Solidity 他是一种只能合约语言开发 我们利用web3将不再依赖后端 而是连接只能合约开发 首先 我们先不用急着写代码 还是要概念为先 首先 我们来对比 WEB1.0到3.0的概念 首先 web1.0 更多处于信…

全网最全、最新MyBatis框架核心知识

MyBatis框架 1. 软件开发常用结构 MyBatis是操作数据库的,相当于是一个增强的JDBC 1.1 三层架构 三层架构包括: 界面层(User Interface layer)业务逻辑层(Business Logic Layer)数据访问层(Dat…

【OpenMMLab AI实战营第二期】MMPretrain基本使用

MMPreTrain 算法库介绍 MMPretrain 是一个全新升级的预训练开源算法框架,旨在提供各种强大的预训练主干网络, 并支持了不同的预训练策略。MMPretrain 源自著名的开源项目 MMClassification 和 MMSelfSup,并开发了许多令人兴奋的新功能。 目前…

八、进程等待

文章目录 一、进程创建(一)fork函数概念1.概念2.父子进程共享fork之前和fork之后的所有代码,只不过子进程只能执行fork之后的! (二)fork之后,操作系统做了什么?1.进程具有独立性,代…

Web Scoket简述

Web Socket 简介 初次接触 Web Socket 的人,我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处? 因为 HTTP 协议有一个缺陷:通信只能由客户端发起。http基于请求响应实现。 (准确来说HTTP…

Java之BigDecimal使用

Java之BigDecimal使用 1、BigDecimal概述 ​ BigDecimal用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计…

Redis的使用规范小建议

Redis 核心技术与实战 笔记 作者: 蒋德钧 毕竟,高性能和节省内存,是我们的两个目标,只有规范地使用Redis,才能真正实现这两个目标。如果说之前的内容教会了你怎么用,那么今天的内容,就是帮助你用…