一、异步爬虫
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)