爬虫的进阶使用——异步爬虫

本文介绍了如何利用异步编程实现Python爬虫的并发下载,涉及asyncio、aiohttp、asyncohttp库的使用,以及selenium进行网页自动化操作。通过实例演示了如何结合aiomultiprocessing加速爬取速度和selenium进行页面交互。
摘要由CSDN通过智能技术生成

一、异步爬虫

1.异步爬虫的了解

  • 在爬取数据下载的时候,通常是下载一个才能下载下一个,我们想要同时来下载节约时间
  • python有限制,只能使用1个满cpu核心。GIL全局锁
  • 想要实现从单线程到并发执行的转换,所以有了异步爬虫

异步:就是说cpu先干完自己的事情,然后去干别的事情,让磁盘去慢慢读取,但时不时会出来看一眼磁盘都没读完,读完了就往下做,没读完就继续做其他事情。

一般来说的话异步是搭配协程来实现的

2.异步模块asnico的了解

import asyncio
from time import sleep

async def request(url):
    print('正在下载:'+url)
    sleep(2)
    print('下载成功'+url)

"""不使用task的情况"""
# # result代表的是一个协程
# result = request(url = 'www.baidu.com')
# # 创建一个循环监视器
# loop = asyncio.get_event_loop()
# # 将携程对象注册到loop循环监视器中,并启动loop循环
# loop.run_until_complete(result)


"""使用单个task任务的对象的时候"""
# <Task pending name='Task-1' coro=<request() running at D:/WorkSpace/pycharmEDU/爬虫spider/test01.py:5>>
# peding表示还未进行任务的状态
task = loop.create_task(result)
print(task)
# <Task finished name='Task-1' coro=<request() done,finishing表示完成任务的状态
loop.run_until_complete(task)
print(task)

  • 异步主要是包括三个部分:一是将循环监视器注册好,而是通过asnico得到一个协程对象的任务,最后就是将任务注册到循环监视器中并执行任务

多任务时的异步

import asyncio
import time



async def request_html(number):
    print('正在下载:',number)
    # 当代码中存在同步代码时,就无法实现异步过程,所以需要将函数挂起
    # time.sleep(2)
    await asyncio.sleep(2)
    print('下载成功',number)
tasks = []
loop = asyncio.get_event_loop()
for i in range(1,3000):
    task = loop.create_task(request_html(i))
    # 将任务添加到任务列表中去
    tasks.append(task)
# 注册循环监视器
loop.run_until_complete(asyncio.wait(tasks))

踩过的坑:虽然create_task与ensure_future的功能是一样的都是注册任务,但是前者的用法是loop.create_task,就是说要通过已经创建的监视器来注册任务,而后者可以直接用asnico来注册任务,不需要提前注册循环监视器

  • session的请求是同步的,如果想要变成异步的,则要await get(url),这样也是同步的结果

3.发起异步访问aiohttp库

  • 基于异步网络来进行请求的

    import aiohttp
    import asyncio
    # 异步访问请求
    async def get(url):
        # 每一步都是需要挂起的
        session = aiohttp.ClientSession()
        response = await session.get(url)
        result = await response.text()
        # 用完之后还需要关闭连接
        await session.close()
        return result
    
    # 调用异步访问的函数,主要是不要忘了await
    async def get_html(url):
        result = await get(url)
    

4.aiomultiprocess库的使用

import aiohttp
import asyncio
from aiomultiprocess import Pool
"""与多进程结合,可以加快爬取的速度"""
# 异步访问请求
async def get(url):
    # 每一步都是需要挂起的
    session = aiohttp.ClientSession()
    response = await session.get(url)
    result = await response.text()
    # 用完之后还需要关闭连接
    await session.close()
    print("下载完成",url)
    return result

# 调用异步访问的函数,主要是不要忘了await
async def request():
    url = 'http://127.0.0.1:5000/aaa'
    urls = [url for _ in range(10)]
    async with Pool() as pool:
        result = await pool.map(get,urls)
        return result

if __name__ == '__main__':
    coroutine = request()
    task = asyncio.ensure_future(coroutine)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(task)

二、异步爬虫的使用

from aiomultiprocess import Pool
import aiohttp
import asyncio
from lxml import etree

re_url = 'https://bd.lianjia.com/ershoufang/pg%s/'
# 利用异步来发起请求,访问的更快些
async def get(url):
    session = aiohttp.ClientSession()
    response = await session.get(url)
    result = await response.text()
    await session.close()
    return result
# 解析的时候不用异步
def parm(html):
    tree = etree.HTML(html)
    for li in tree.xpath('//ul[@class="sellListContent"]/li/div[@class="info clear"]'):
        title = li.xpath('./div[1]/a/text()')[0]
        address= li.xpath('./div[2]/div//text()')[0]
        houseInfo = li.xpath('./div[3]/div//text()')[0]
        followInfo = li.xpath('./div[4]//text()')[0]
        totalprice = li.xpath('./div[6]/div[1]//text()')[0]
        unitprice = li.xpath('./div[6]/div[2]//text()')[0]
        print(title,address,houseInfo,followInfo,totalprice,unitprice)
        # break

# 定义一个可以用来创造携程的函数
async def get_html(url):
    # print('正在采集网址:',url)
    response = await get(url)
    parm(response)

tasks = []
for page in range(1,50):
    corontinue = get_html(re_url % page)
    task = asyncio.ensure_future(corontinue)
    tasks.append(task)

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

三、selenium

selenium这个就相当于用电脑来代替人来操作,达到浏览网页的效果

1.selenium的基本使用

from selenium import webdriver
# 查找元素要用到By
from selenium.webdriver.common.by import By

# 在使用selenium一定要注意版本要对应,然后电脑上要有对应的浏览器
browser = webdriver.Chrome(executable_path='')  # 创建一个谷歌浏览器
# browser.maximize_window()  # 浏览器的最大化显示
# browser.minimize_window()  # 浏览器的最小化显示
browser.set_window_size(400,400) # 设置浏览器的宽和高
browser.get(url='https://www.baidu.com')

# 通过ID来定位元素
browser.find_element(By.ID,'kw').send_keys('selenium')
# 通过类名来定位元素
browser.find_element(By.CLASS_NAME,'s_ipt').send_keys('selenium')
# 通过CSSZ选择器来定位元素
browser.find_element(By.CSS_SELECTOR,'#kw').send_keys('selenium')
# 通过Ixpath定位元素
browser.find_element(By.XPATH,'//*[@id="kw"]').send_keys('selenium')
# 写入关键词之后就是点击执行
browser.find_element(By.ID,'su').click()

如果出现嵌套网页的情况,一般的话就是将网页定位到包含里面那个网页的标签下面。

browser.switch_to.frame(0) #定位到第一个frame标签中去

2.selenium动作链的使用

from selenium import webdriver
# 查找元素要用到By
from selenium.webdriver.common.by import By

from selenium.webdriver import ActionChains
# 在使用selenium一定要注意版本要对应,然后电脑上要有对应的浏览器
browser = webdriver.Chrome(executable_path='')  # 创建一个谷歌浏览器
# browser.maximize_window()  # 浏览器的最大化显示
# browser.minimize_window()  # 浏览器的最小化显示
browser.set_window_size(400,400) # 设置浏览器的宽和高
browser.get(url='https://www.baidu.com')
# 定位到frame标签
browser.switch_to.frame(0)
div = browser.find_element(By.ID,'su')
action = ActionChains(browser)
# 点击并坚持住,不松手
action.click_and_hold(div)
for i in range(5):
    action.move_by_offset(20,0).perform()
# 隐形等待,超过了等待时间,就会执行下一步
browser.implicitly_wait(60)
action.drag_and_drop_by_offset(div,150,0).perform()
action.release()
"""
有时候网页刷新慢,需要等待这时就分为显性等待隐形等待
1.显性等待就是sleep
"""
"""显示等待和隐式等待都是"""
WebDriverWait(browser,10)
# 预期判断方法
from selenium.webdriver.support import expected_conditions as EC
# 显示等待
wait =WebDriverWait(browser,10)
# 判断是否有title,返回的是bool值
wait.until(EC.title_is('百度一下,你就知道'))
# 判断是否包含有预期的字符串,返回的也是bool值
wait.until(EC.title_is('百度一下,你就知道'))


from selenium.webdriver import ActionChains, Keys
# 通过键盘来敲击回车
browser.find_element(By.ID,'kw').send_keys(Keys.ENTER)

3.selenium实战

from selenium.webdriver.common.by import By
from selenium import webdriver
from lxml import etree
driver = webdriver.Chrome(executable_path='')
driver.maximize_window()
driver.get('https://www.zhipin.com/?sid=sem_pz_bdpc_dasou_title')

driver.find_element(By.CLASS_NAME,'ipt-search').send_keys('python开发')
driver.find_element(By.CLASS_NAME,'btn-search').click()
# 隐形等待10s
driver.implicitly_wait(10)
lis = driver.find_elements(By.CLASS_NAME,'job-primary')
for li in lis:
    # 针对每一个职位点击
    li.click()
    driver.implicitly_wait(10)
    # 获取句柄——就是为了浏览器之间的页面切换
    handles = driver.window_handles
    # 切换到最后一个页面
    driver.switch_to.window(handles[-1])
    # 获取页面的元数据
    html = driver.page_source
    tree = etree.HTML(html)
    name = tree.xpath('//div[@class="detail-op"]/h2//text()')[0]
    print(name)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Indra_ran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值