pyppeteer github地址:https://github.com/miyakogi/pyppeteer

pyppeteer 英文文档地址: https://miyakogi.github.io/pyppeteer/

pyppeteer 官方文档 API Reference:

https://miyakogi.github.io/pyppeteer/reference.html

puppeteer(Nodejs版 selenium)快速入门:

https://blog.csdn.net/freeking101/article/details/91542887

爬虫界又出神器 | 一款比selenium更高效的利器:

https://blog.csdn.net/chen801090/article/details/93216278

python爬虫利器 pyppeteer(模拟浏览器)实战:

https://blog.csdn.net/xiaoming0018/article/details/89841728

Pyppeteer 简介

 

提起 selenium 想必大家都不陌生,作为一款知名的 Web 自动化测试框架,selenium 支持多款主流浏览器,提供了功能丰富的API 接口,经常被我们用作爬虫工具来使用。但是 selenium 的缺点也很明显,比如速度太慢、对版本配置要求严苛,最麻烦是经常要更新对应的驱动。还有些网页是可以检测到是否是使用了selenium。并且selenium 所谓的保护机制不允许跨域 cookies 保存以及登录的时候必须先打开网页然后后加载 cookies 再刷新的方式很不友好。

今天就给大家介绍另一款 web 自动化测试工具 Pyppeteer,虽然支持的浏览器比较单一,但在安装配置的便利性和运行效率方面都要远胜 selenium。

介绍 Pyppeteer 之前先说一下 Puppeteer,Puppeteer 是 Google 基于 Node.js 开发的一个工具,主要是用来操纵 Chrome  浏览器的 API,通过 Javascript 代码来操纵 Chrome 浏览器的一些操作,用作网络爬虫完成数据爬取、Web 程序自动测试等任务。其 API 极其完善,功能非常强大。 而 Pyppeteer 又是什么呢?它实际上是 Puppeteer 的 Python 版本的实现,但他不是 Google 开发的,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。

Pyppeteer 其实是 Puppeteer 的 Python 版本。pyppeteer 模块看不懂就去看puppeteer文档,pyppeteer 只是在 puppeteer之上稍微包装了下而已 。

注意:本来 chrome 就问题多多,puppeteer 也是各种坑,加上 pyppeteer 是基于前者的改编 python 版本,也就是产生了只要前两个有一个有 bug,那么 pyppeteer 就会原封不动的继承下来,本来这没什么,但是现在遇到的问题就是 pyppeteer 这个项目从2018年9月份之后几乎没更新过,前两者都在不断的更新迭代,而 pyppeteer 一直不更新,导致很多 bug 根本没人修复。

 

下面简单介绍下Pyppeteer的两大特点:chromium浏览器和asyncio框架:

1).chromium

Chromium 是一款独立的浏览器,是 Google 为发展自家的浏览器 Google Chrome 而开启的计划,相当于 Chrome的实验版,且 Chromium 是完全开源的。二者基于相同的源代码构建,Chrome 所有的新功能都会先在 Chromium 上实现,待验证稳定后才会移植,因此 Chromium 的版本更新频率更高,也会包含很多新的功能,但作为一款独立的浏览器,Chromium 的用户群体要小众得多。两款浏览器“同根同源”,它们有着同样的 Logo,但配色不同,Chrome 由蓝红绿黄四种颜色组成,而 Chromium 由不同深度的蓝色构成。

Pyppeteer 的 web 自动化是基于 chromium 来实现的,由于 chromium 中某些特性的关系,Pyppeteer 的安装配置非常简单,关于这一点稍后我们会详细介绍。

 

2).asyncio

asyncio 是 Python 的一个异步协程库,自3.4版本引入的标准库,直接内置了对异步IO的支持,号称是Python最有野心的库,官网上有非常详细的介绍:https://docs.python.org/3/library/asyncio.html

安装与使用

 

由于 Pyppeteer 采用了 Python 的 async 机制,所以其运行要求的 Python 版本为 3.5 及以上

 

1).极简安装

使用 pip3 install pyppeteer 命令就能完成 pyppeteer 库的安装,至于 chromium 浏览器,只需要一条 pyppeteer-install 命令就会自动下载对应的最新版本 chromium 浏览器到 pyppeteer 的默认位置。

window 下 安装完 pyppeteer ,会在 python 安装目录下的 Scripts 目录下 有 pyppeteer-install.exe 和 pyppeteer-install-script.py 两个文件,执行 任意一个都可以安装 chromium 浏览器到 pyppeteer 的默认位置。

运行 pyppeteer-install.exe :

如果不运行 pyppeteer-install 命令,在第一次使用 pyppeteer 的时候也会自动下载并安装 chromium 浏览器,效果是一样的。总的来说,pyppeteer 比起 selenium 省去了 driver 配置的环节。

当然,出于某种原因(需要梯子,或者科学上网),也可能会出现chromium自动安装无法顺利完成的情况,这时可以考虑手动安装:首先,从下列网址中找到自己系统的对应版本,下载chromium压缩包;

'linux': 'https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/575458/chrome-linux.zip'
'mac': 'https://storage.googleapis.com/chromium-browser-snapshots/Mac/575458/chrome-mac.zip'
'win32': 'https://storage.googleapis.com/chromium-browser-snapshots/Win/575458/chrome-win32.zip'
'win64': 'https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/575458/chrome-win32.zip'

然后,将压缩包放到pyppeteer的指定目录下解压缩,windows系统的默认目录。

其他系统下的默认目录可以参照下面:

Details see appdirs’s user_data_dir.

好了,安装完成之后我们命令行下测试下:
>>> import pyppeteer
如果没有报错,那么就证明安装成功了。

 

2).使用

Pyppeteer 是一款非常高效的 web 自动化测试工具,由于 Pyppeteer 是基于 asyncio 构建的它的所有 属性 和方法 几乎都是 coroutine (协程) 对象因此在构建异步程序的时候非常方便,天生就支持异步运行。

程序构建的基本思路是新建 一个 browser 浏览器 和 一个 页面 page。

看下面这段代码,在 main 函数中,先是建立一个浏览器对象,然后打开新的标签页,访问百度主页,对当前页面截图并保存为“example.png”,最后关闭浏览器。前文也提到过,pyppeteer 是基于 asyncio 构建的,所以在使用的时候需要用到 async/await 结构。

import asyncio
from pyppeteer import launchasync def main():browser = await launch()page = await browser.newPage()await page.goto('http://baidu.com')await page.screenshot({'path': 'example.png'})await browser.close()asyncio.get_event_loop().run_until_complete(main())

运行上面这段代码会发现并没有浏览器弹出运行,这是因为 Pyppeteer 默认使用的是无头浏览器,如果想要浏览器显示,需要在launch 函数中设置参数 “headless =False”,程序运行结束后在同一目录下会出现截取到的网页图片:

 

遇到的错误

 

控制访问指定 url 之后 await page.goto(url),会遇到上面的错误,如果这时候使用了 sleep 之类的延时也会出现这个错误或者类似的 time out。 
这个问题是 puppeteer 的 bug,但是对方已经修复了,而 pyppeteer 迟迟没更新,就只能靠自己了,搜了很多人的文章,例如:https://github.com/miyakogi/pyppeteer/issues/171 ,但是我按照这个并没有成功。也有人增加一个函数,但调用这个参数依然没解决问题。

async def scroll_page(page):cur_dist = 0height = await page.evaluate("() => document.body.scrollHeight")while True:if cur_dist < height:await page.evaluate("window.scrollBy(0, 500);")await asyncio.sleep(0.1)cur_dist += 500else:break

可以把 python 第三方库 websockets 版本 7.0 改为 6.0 就可以了,亲测可用。

pip uninstall websockets  #卸载websocketspip install websockets==6.0
或者
pip install websockets==6.0 --force-reinstall #指定安装6.0版本

解决这个问题的方法就是浏览器初始化的时候添加'dumpio':True。

# 启动 pyppeteer 属于内存中实现交互的模拟器

browser = await launch({'headless': False, 'args': ['--no-sandbox'], 'dumpio': True})

需要设置浏览器显示大小,默认就是无法正常显示。可以看到页面左侧右侧都是空白,网站内容并没有完整铺满chrome.

# Pyppeteer支持字典和关键字传参,Puppeteer只支持字典传参
# 这里使用字典传参
browser = await launch({'headless': False,'dumpio': True,'autoClose': False,'args': ['--no-sandbox','--window-size=1366,850']}
)
await page.setViewport({'width': 1366, 'height': 768})

通过上面设置Windows-size和Viewport大小来实现网页完整显示。

但是对于那种向下无线加载的长网页这种情况如果浏览器是可见状态会显示不全,针对这种情况的解决方法就是赋值当前网页新开一个标签页粘贴进去就正常了。

Pyppeteer 和 Puppeteer 的 不同点

# Puppeteer只支持字典传参
browser = await launch({'headless': True})# Pyppeteer支持字典和关键字传参
browser = await launch({'headless': True})
browser = await launch(headless=True)
# Puppeteer使用$符号
Page.$()/Page.$$()/Page.$x()# Pyppeteer使用Python风格的函数名
Page.querySelector()/Page.querySelectorAll()/Page.xpath()
# 简写方式为:
Page.J(), Page.JJ(), and Page.Jx()

Puppeteer的evaluate()方法使用JavaScript原生函数或JavaScript表达式字符串。Pyppeteer的evaluate()方法只使用JavaScript字符串,该字符串可以是函数也可以是表达式,Pyppeteer会进行自动判断。但有时会判断错误,如果字符串被判断成了函数,并且报错,可以添加选项force_expr=True, 强制Pyppeteer作为表达式处理。

获取页面内容:

content = await page.evalute('document.body.textContent', force_expr=True)

获取元素的内部文字:

element = await page.querySelector('h1')
title = await page.evaluate('(element) => element.textContent', element)

基础用法

 

抓取内容  可以使用 xpath 表达式

"""
# Pyppeteer三种解析方式
Page.querySelector()  # 选择器
Page.querySelectorAll()
Page.xpath()    # xpath表达式
# 简写方式为:
Page.J(), Page.JJ(), and Page.Jx()
"""

示例1:

import asyncio
from pyppeteer import launchasync def main():# headless参数设为False,则变成有头模式# Pyppeteer支持字典和关键字传参,Puppeteer只支持字典传参# 指定引擎路径# exepath = r'C:\Users\Administrator\AppData\Local\pyppeteer\pyppeteer\local-chromium\575458\chrome-win32/chrome.exe'# browser = await launch({'executablePath': exepath, 'headless': False, 'slowMo': 30})browser = await launch(# headless=False,{'headless': False})page = await browser.newPage()# 设置页面视图大小await page.setViewport(viewport={'width': 1280, 'height': 800})# 是否启用JS, enabled设置为False, 则无渲染效果await page.setJavaScriptEnabled(enabled=True)# 超时间见 1000 毫秒res = await page.goto('https://www.toutial.com/', options={'timeout': 1000})resp_headers = res.headers # 响应头resp_status = res.status # 响应状态# 等待await asyncio.sleep(2)# 第二种方法,在while循环里强行查询某元素进行等待while not await page.querySelector('.t'):pass# 滚动到页面底部await page.evaluate('window.scrollBy(0, document.body.scrollHeight)')await asyncio.sleep(2)# 截图 保存图片await page.screenshot({'path': 'toutiao.png'})# 打印页面cookiesprint(await page.cookies())""" 打印页面文本 """# 获取所有html内容print(await page.content())# 在网页上执行js 脚本dimensions = await page.evaluate(pageFunction='''() => {return {width: document.documentElement.clientWidth, // 页面宽度height: document.documentElement.clientHeight, // 页面高度deviceScaleFactor: window.devicePixelRatio,  //像素比 1.0000000149011612}}''', force_expr=False)  # force_expr=False  执行的是函数print(dimensions)# 只获取文本执行js脚本force_expr 为True则执行的是表达式content = await     page.evaluate(pageFunction='document.body.textContent', force_expr=True)print(content)# 打印当前页标题print(await page.title())# 抓取新闻内容 可以使用xpath表达式"""# Pyppeteer 三种解析方式Page.querySelector()  # 选择器Page.querySelectorAll()Page.xpath()  # xpath表达式# 简写方式为:Page.J(), Page.JJ(), and Page.Jx()"""element = await page.querySelector(".feed-infinite-wrapper > ul>li")         # 只抓取一个print(element)# 获取所有文本内容  执行jscontent = await page.evaluate('(element) => element.textContent', element)print(content)# elements = await page.xpath('//div[@class="title-box"]/a')elements = await page.querySelectorAll(".title-box a")for item in elements:print(await item.getProperty('textContent'))# <pyppeteer.execution_context.JSHandle object at 0x000002220E7FE518># 获取文本title_str = await(await     item.getProperty('textContent')).jsonValue()# 获取链接title_link = await(await item.getProperty('herf')).jsonValue()print(title_str)print(title_link)# 关闭浏览器await browser.close()asyncio.get_event_loop().run_until_complete(main())

示例2:

import asyncio
import pyppeteer
from collections import namedtupleheaders = {'date': "Sun, 28 Apr 2019 06:50:20 GMT','server': "Cmcc','x-frame-options': "SAMORIGIN\nSAMEORIGIN','last-modified': 'Fir, 26 Apr 2019 09:58:09 GMT','accept-ranges': 'bytes','cache-control': 'max-age=42300','expires': 'Sun, 28 Apr 2019 18:50:20 GMT','vary': 'Accept-Encoding,User-Agent','content-encoding": 'gzip','content-length': 'gzip','content-length': '19823','connection': 'Keep-alive','via': '1.1 ID-0314217270751344 uproxy-17'
}Response = namedtuple("rs", "title url html cookies headers history status")async def get_html(url):browser = await pyppeteer.launch(headless=True, args=['--no-sandbox'])page = await browser.newPage()res = await page.goto(url, options={'timeout': 10000})data = await page.content()title = await page.title()resp_cookies = await page.cookies() # cookieresp_headers = res.headers # 响应头resp_status = res.status # 响应状态print(data)print(title)print(resp_headers)print(resp_status)return titleif __name_ '__main__':url_list = ["https://www.toutiao.com","http://jandan.net/ooxx/page-8#comments","https://www.12306.cn/index"]task = [get_html(url) for url in url_list]loop = asyncio.get_event_loop()results = loop.run_until_complete(asyncio.gather(*task))for res in results:print(res)

模拟输入

模拟输入文本:

# 模拟输入 账号密码 {'delay': rand_int()} 为输入时间
await page.type('#TPL_username_1', "sadfsdfsadf")
await page.type('#TPL_password_1', "123456789",)await page.waitFor(1000)
await page.click("#J_SubmitStatic")

使用tkinter获取页面高度 宽度

def screen_size():"""使用tkinter获取屏幕大小"""import tkintertk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return width, height

爬取京东商城

示例代码:

import requests
from bs4 import BeautifulSoup
from pyppeteer import launch
import asynciodef screen_size():"""使用tkinter获取屏幕大小"""import tkintertk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return width, heightasync def main(url):# browser = await launch({'headless': Flase, 'args': ['--no-sandbox'], })browser = await launch({'args': ['--no-sandbox'], })page = await browser.newPage()width, height = screen_size()await page.setViewport(viewport={"width": width, "height": height})await page.setJavaScriptEnabled(enabled=True)await page.setUserAgent('Mozilla/5.0 (windows NT 10.0; Win64; x64) AppleWebKit/537.36 ''(KHTML, like Geck) Chrome/58.0.3029.110 Safri/537.36 Edge/16.16299')await page.goto(url)# await asyncio.sleep(2)await page.evaluate('window.scrollBy(0, document.body.scrollHeight)')await asyncio.sleep(1)# content = await page.content()li_list = await page.xpath('//*[@id="J_goodsList"]/url/li')# print(li_list)item_list = []for li in li_list:a = await li.xpath('.//div[@class="p-img"]/a')detail_url = await (await a[0].getProperty("href")).jsonValue()promo_words = await (await a[0].getProperty("title")).jsonValue()a_ = await li.xpath('.//div[@class="p-commit"]/strong/a')p_commit = await (await a_[0].getProperty("textContent")).jsonValue()i = await li.xpath('./div/div[3]/strong/i')price = await (await i[0].getProperty("textContent")).jsonValue()em = await li.xpath('./div/div[4]/a/em')title = await (await em[0].getProperty("textContent")).jsonValue()item = {"title": title,"detail_url": detail_url,"promo_words": promo_words,'p_commit': p_commit,'price': price}item_list.append(item)# print(item)# break# print(content)await page_close(browser)return item_listasync def page_close(browser):for _page in await browser.pages():await _page.close()await browser.close()msg = "手机"url = "https://search.jd.com/Search?keyword={}&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq={}&cid2=653&cid3=655&page={}"
task_list = []
for i in range(1, 6):page = i * 2 - 1url = url.format(msg, msg, page)task_list.append(main(url))loop = asyncio.get_event_loop()
results = loop.run_until_complete(asyncio.gather(*task_list))
# print(results, len(results))
for i in results:print(i, len(i))print('*' * 100)
# soup = BeautifulSoup(content, 'lxml')
# div = soup.find('div', id='J_goodsList')
# for i, li in enumerate(div.find_all('li', class_='gl-item')):
#    if li.select('.p-img a'):
#        print(li.select('.p-img a')[0]['href'], i)
#        print(li.select('.p-price i')[0].get_text(), i)
#        print(li.select('.p-name em')[0].text, i)
#    else:
#        print("#" * 200)
#        print(li)

抓取淘宝

示例代码:

# -*- coding: urf-8 -*-import time
import random
import asyncio
from retrying import retry # 错误自动重试
from pyppeteer.launcher import launchjs1 = '''() =>{Object.defineProperties(navigator, {webdriver:{ get: () => false}})}'''
js2 = '''() => {alert(window.navigator.webdriver)}'''
js3 = '''() => {window.navigator.chrome = {runtime: {}, }; }'''
js4 = '''() => {Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});}'''
js5 = '''() => {Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5, 6],});}'''def retry_if_result_none(result):return result is None@retry(retry_on_result=retry_if_result_none, )
async def mouse_slide(page=None):await asyncio.sleep(3)try:await page.hover('#nc_1_n1z')await page.mouse.down()await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})await page.mouse.up()except Exception as e:print(e, '    : slide login False')return Noneelse:await asyncio.sleep(3)slider_again = await page.Jeval('.nc-lang-cnt', 'node => node.textContent')if slider_again != '验证通过':return Noneelse:await page.screenshot({'path': './headless-slide-result.png'})print('验证通过')return 1
def input_time_random():return random.randint(100, 151)def screen_size():"""使用tkinter获取屏幕大小"""import tkintertk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return width, heightasync def main(username, pwd, url):browser = await launch({'headless': False, 'args': ['--no-sandbox'], },userDataDir = './userdata',args=['--window-size=1366,768'])page = await browser.newPage()width, height = screen_size()await page.setViewport(viewport={"width": width, "height": height})await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ''(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299')await page.goto(url)await page.evaluate(js1)await page.evaluate(js3)await page.evaluate(js4)await page.evaluate(js5)pwd_login = await page.querySelector('.J_Quick2Static')# print(await (await pwd_Login.getProperty('textContent')).jsonValue())await pwd_login.click()await page.type('#TPL_username_1', username, {'delay': input_time_random() - 50})await page.type('#TPL_password_1', pwd, {'delay': input_time_random()})await page.screenshot({'path': './headless-test-result.png'})time.sleep(2)slider = await page.Jeval('#nocaptcha', 'node => node.style') # 是否有滑块if slider:print('出现滑块情况判定')await page.screenshot({'path': './headless-login-slide.png'})flag = await mouse_slide(page=page)if flag:print(page.url)await page.keyboard.press('Enter')await get_cookie(page)else:await page.keyboard.press('Enter')await page.waitFor(20)await page.waitForNavigation()try:global errorerror = await page.Jeval('.error', 'node => node.textContent')except Exception as e:error = Noneprint(e, "错啦")finally:if error:print('确保账户安全重新输入')else:print(page.url)# 可继续网页跳转 已经携带 cookie# await get_search(page)await get_cookie(page)await page_close(browser)async def page_close(browser):for _page in await browser.pages():await _page.close()await browser.close()async def get_search(page):# https://s.taobao.com/search?q={查询的条件}&p4ppushleft=1%2C48&s={每页 44 条 第一页 0 第二页 44}&sort=sale-descawait page.goto("https://s.taobao.com/search?q=气球")await asyncio.sleep(5)# print(await page.content())# 获取登录后cookie
async def get_cookie(name):res = await page.content()cookies_list = await page.cookies()cookies = ''for cookie in cookies_list:str_cookie = '{0}={1};'str_cookie = str_cookie.format(cookie.get('name'), cookie.get('value'))cookies += str_cookieprint(cookies)# 将coookie放入cookie池 以便多次请求 封账号 利用cookie对搜索内容进行爬取return cookiesif __name__ == '__main__':tb_username = '淘宝用户名'tb_pwd = '淘宝密码'tb_url = "https://login.taobao.com/member/login.jhtml"loop = asyncio.get_event_loop()loop.run_until_complete(main(tb_username, tb_pwd, tb_url))

利用 上面 获取到的 cookie 爬取搜索内容

示例代码:

import json
import requests
import re# 设置cookie 池 随机发送请求 通过pyppeteer获取cookie
cookie = '_tb_token_=edd7e354dee53;t=fed8f4ca1946ca1e73223cfae04bc589;sg=20f;cna=2uJSFdQGmDMCAbfFWXWAC4Jv;cookie2=1db6cd63ad358170ea13319f7a862c33;_l_g_=Ug%3D%3D;v=0;unb=3150916610;skt=49cbfd5e01d1b550;cookie1=BxVRmD3sh19TaAU6lH88bHw5oq%2BgcAGcRe229Hj5DTA%3D;csg=cf45a9e2;uc3=vt3=F8dByEazRMnQZDe%2F9qI%3D&id2=UNGTqfZ61Z3rsA%3D%3D&nk2=oicxO%2BHX4Pg%3D&lg2=U%2BGCWk%2F75gdr5Q%3D%3D;existShop=MTU1Njg3MDM3MA%3D%3D;tracknick=%5Cu7433150322;lgc=%5Cu7433150322;_cc_=V32FPkk%2Fhw%3D%3D;mt=ci=86_1;dnk=%5Cu7433150322;_nk_=%5Cu7433150322;cookie17=UNGTqfZ61Z3rsA%3D%3D;tg=0;enc=tThHs6Sn3BAl8v1fu3J4tMpgzA1n%2BLzxjib0vDAtGsXJCb4hqQZ7Z9fHIzsN0WghdcKEsoeKz6mBwPUpyzLOZw%3D%3D;JSESSIONID=B3F383B3467EC60F8CA425935232D395;l=bBMspAhrveV5732DBOCanurza77OSIRYYuPzaNbMi_5pm6T_G4QOlC03xF96VjfRswYBqh6Mygv9-etuZ;hng=CN%7Czh-CN%7CCNY%7C156;isg=BLi41Q8PENDal3xUVsA-aPbfiWaKiRzB6vcTu_IpBPOmDVj3mjHsO86vxUQYW9SD;uc1=cookie16=W5iHLLyFPlMGbLDwA%2BdvAGZqLg%3D%3D&cookie21=W5iHLLyFeYZ1WM9hVnmS&cookie15=UIHiLt3xD8xYTw%3D%3D&existShop=false&pas=0&cookie14=UoTZ4ttqLhxJww%3D%3D&tag=8&lng=zh_CN;thw=cn;x=e%3D1%26p%3D*%26s%3D0%26c%3D0%26f%3D0%26g%3D0%26t%3D0;swfstore=34617;'headers = {'cookie': cookie,"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
}rep = requests.get('https://s.taobao.com/search?q=手机&p4ppushleft=1%2C48&s=0&sort=sale-desc ', headers=headers)
rep.encoding = 'utf-8'
res = rep.text
print(res)r = re.compile(r'g_page_config = (.*?)g_srp_loadCss', re.S)
res = r.findall(res)data = res[0].strip().rstrip(';')
dic_data = json.loads(data)
auctions = dic_data.get('mods')['itemlist']['data']['auctions']# print(auctions, len(auctions))
for item in auctions[1:]:print(item)break

针对iframe 的操作

from pyppeteer import launch
import asyncioasync def main(url):w = await launch({'headless': False, 'args': ['--no-sandbox'], })page = await w.newPage()await page.setViewport({"width": 1366, 'height': 800})await page.goto(url)try:await asyncio.sleep(1)frame = page.framesprint(frame) # 需要找到哪一个frametitle = await frame[1].title()print(title)await asyncio.sleep(1)login = await frame[1].querySelector('#switcher_plogin')print(login)await login.click()await asyncio.sleep(20)except Exception as e:print(e, "EEEEEEEEE")for _page in await w.pages():await _page.close()await w.close()asyncio.get_event_loop().run_until_complete(main("https://i.qq.com/?rd=1"))
# asyncio.get_event_loop().run_until_complete(main("https://www.gushici.com/"))

与 scrapy 的整合

加入downloadmiddleware

from scrapy import singals
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
import random
import pyppeteer
import asyncio
import os
from scrapy.http import HtmlResponsepyppeteer.DEBUG = Falseclass FundscrapyDownloaderMiddleware(object):# Not all methods nned to be defined. If a method is not defined,# scrapy acts as if the downloader middleware does not modify the # passed objects.def __init__(self):print("Init downloaderMiddleware use pypputeer.")os.environ['PYPPETEER_CHROMIUM_REVISION'] = '588429'# pyppeteer.DEBUG = Falseprint(os.environ.get('PYPPETEER_CHROMIUM_REVISION'))loop = asyncio.get_event_loop()task = asyncio.ensure_future(self.getbrowser())loop.run_until_complete(task)# self.browser = task.result()print(self.browser)print(self.page)# self.page = await browser.newPage()async def getbrowser(self):self.browser = await pyppeteer.launch()self.page = await self.browser.newPage()# return await pyppeteer.launch()async def getnewpage(self):return await self.browser.newPage()@classmethoddef from_crawler(cls, crawler):# This method is used by Scrapy to create your spiders.s = cls()crawler.singlas.connect(s.spider_opened, signal=signals.spider_opened)return sdef process_request(self, request, spider):# Called for each request that goes through the downloader# middleware# Must either:# - return None: continue processing this request# - or return a Response object# - or return a Request object# - or raise IgnoreRequest: process_exception() methods of# installed downloader middleware will be calledloop = asyncio.get_event_loop()task = asyncio.ensure_future(self.usePypuppeteer(request))loop.run_until_complete(task)# return task.result()return HtmlResponse(url=request.url, body=task.result(), encoding="utf-8",request=request)async def usePypuppeteer(self, request):print(request.url)# page = await self.browser.newPage()await self.page.goto(request.url)content = await self.page.content()return content def process_response(self, request, response, spider):# Called with the response returned from the downloader.# Must either:# - return a Response object# - return a Request object# - or raise IgnoreRequestreturn responsedef process_exception(self, request, exception, spider):# Called when a download handler or a process_request()# (from other downloader middleware) raises an exception.# Must either:# - return None: continue processing this exception# - return a Response object: stops process_exception() chain# - return a Request object: stops process_exception() chainpassdef spider_opened(self, spider):spider.logger.info('Spider opened: %s' %spider.name)

实战 异步爬取

 

示例 1 :快速上手

接下来我们测试下基本的页面渲染操作,这里我们选用的网址为:http://quotes.toscrape.com/js/,这个页面是JavaScript渲染而成的,用基本的requests库请求得到的HTML结果里面是不包含页面中所见的条目内容的。

为了证明requests无法完成正常的抓取,我们可以先用如下代码来测试一下:

import requests
from pyquery import PyQuery as pqurl = 'http://quotes.toscrape.com/js/'
response = requests.get(url=url)
doc = pq(response.text)
print('Quotes : {0}'.format(doc('.quote').length))# 结果
# Quotes : 0

这里首先使用requests来请求网页内容,然后使用pyquery来解析页面中的每一个条目。观察源码之后我们发现每个条目的class名为quote,所以这里选用了.quote这个CSS选择器来选择,最后输出条目数量。

运行结果: Quotes: 0

结果是0,这就证明使用requests是无法正常抓取到相关数据的。

为什么?

因为这个页面是JavaScript渲染而成的,我们所看到的内容都是网页加载后又执行了JavaScript之后才呈现出来的,因此这些条目数据并不存在于原始HTML代码中,而requests仅仅抓取的是原始HTML代码。

好的,所以遇到这种类型的网站我们应该怎么办呢?

其实答案有很多:

  1. 分析网页源代码数据,如果数据是隐藏在 HTML 中的其他地方,以 JavaScript 变量的形式存在,直接提取就好了。
  2. 分析 Ajax,很多数据可能是经过 Ajax 请求时候获取的,所以可以分析其接口。
  3. 模拟 JavaScript 渲染过程,直接抓取渲染后的结果。

而 Pyppeteer 和 Selenium 就是用的第三种方法,下面我们再用 Pyppeteer 来试试,如果用 Pyppeteer 实现如上页面的抓取的话,代码就可以写为如下形式:

import asyncio
from pyppeteer import launch
from pyquery import PyQuery as pqasync def main():browser = await launch()page = await browser.newPage()url = 'http://quotes.toscrape.com/js/'await page.goto(url=url)doc = pq(await page.content())print('Quotes : {0}'.format(doc('.quote').length))await browser.close()asyncio.get_event_loop().run_until_complete(main())

运行结果:Quotes: 10
看运行结果,这说明我们就成功匹配出来了 class 为 quote 的条目,总数为 10 条,具体的内容可以进一步使用 pyquery 解析查看。

那么这里面的过程发生了什么?

实际上,Pyppeteer 整个流程就完成了浏览器的开启、新建页面、页面加载等操作。另外 Pyppeteer 里面进行了异步操作,所以需要配合 async/await 关键词来实现。首先, launch 方法会新建一个 Browser 对象,然后赋值给 browser,然后调用 newPage 方法相当于浏览器中新建了一个选项卡,同时新建了一个 Page 对象。然后 Page 对象调用了 goto 方法就相当于在浏览器中输入了这个 URL,浏览器跳转到了对应的页面进行加载,加载完成之后再调用 content 方法,返回当前浏览器页面的源代码。然后进一步地,我们用 pyquery 进行同样地解析,就可以得到 JavaScript 渲染的结果了。另外其他的一些方法如调用 asyncio 的 get_event_loop 等方法的相关操作则属于 Python 异步 async 相关的内容了,大家如果不熟悉可以了解下 Python 的 async/await 的相关知识。好,通过上面的代码,我们就可以完成 JavaScript 渲染页面的爬取了。

模拟网页截图,保存 PDF,执行自定义的 JavaScript 获得特定的内容

接下来我们再看看另外一个例子,这个例子可以模拟网页截图,保存PDF,另外还可以执行自定义的JavaScript获得特定的内容,代码如下:

import asyncio
from pyppeteer import launchasync def main():browser = await launch()page = await browser.newPage()url = 'http://quotes.toscrape.com/js/'await page.goto(url=url)await page.screenshot(path='test_screenshot.png')await page.pdf(path='test_pdf.pdf')# 在网页上执行js 脚本dimensions = await page.evaluate(pageFunction='''() => {return {width: document.documentElement.clientWidth, //页面宽度height: document.documentElement.clientHeight, //页面高度deviceScaleFactor: window.devicePixelRatio,     // 像素比 1.0000000149011612}}''', force_expr=False)  # force_expr=False 执行的是函数print(dimensions)await browser.close()asyncio.get_event_loop().run_until_complete(main())# 结果
# {'width': 800, 'height': 600,'deviceScaleFactor': 1}

这里我们又用到了几个新的 API,完成了网页截图保存、网页导出 PDF 保存、执行 JavaScript 并返回对应数据。

 evaluate 方法执行了一些 JavaScript,JavaScript 传入的是一个函数,使用 return 方法返回了网页的宽高、像素大小比率三个值,最后得到的是一个 JSON 格式的对象。

总之利用 Pyppeteer 我们可以控制浏览器执行几乎所有动作,想要的操作和功能基本都可以实现,用它来自由地控制爬虫当然就不在话下了。

了解了基本的实例之后,我们再来梳理一下 Pyppeteer 的一些基本和常用操作。Pyppeteer 的几乎所有功能都能在其官方文档的 API Reference 里面找到,链接为:https://miyakogi.github.io/pyppeteer/reference.html,用到哪个方法就来这里查询就好了,参数不必死记硬背,即用即查就好。

登录淘宝 (打开网页后,手动输入用户名和密码,可以看到正常跳转到登录后的页面):

import asyncio
from pyppeteer import launchwidth, height = 1366, 768js1 = '''() =>{Object.defineProperties(navigator,{ webdriver:{ get: () => false}})}'''
js2 = '''() => {alert(window.navigator.webdriver)}'''
js3 = '''() => {window.navigator.chrome = {runtime: {}, }; }'''
js4 = '''() =>{Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});}'''
js5 = '''() =>{Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5,6],});}'''async def page_evaluate(page):# 替换淘宝在检测浏览时采集的一些参数# 需要注意,在测试的过程中发现登陆成功后页面的该属性又会变成True# 所以在每次重新加载页面后要重新设置该属性的值。await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')async def main():browser = await launch(headless=False,# userDataDir='./userdata',args=['--disable-infobars', f'--window-size={width},{height}', '--no-sandbox'])page = await browser.newPage()await page.setViewport({"width": width,"height": height})url = 'https://www.taobao.com'await page.goto(url=url)# await page.evaluate(js1)# await page.evaluate(js3)# await page.evaluate(js4)# await page.evaluate(js5)await page_evaluate(page)await asyncio.sleep(100)# await browser.close()asyncio.get_event_loop().run_until_complete(main())

如果把上面 js 去掉,发现淘宝可以检测出来, 跳转不到登录后的页面。

window.navigator 对象包含有关访问者浏览器的信息:https://www.runoob.com/js/js-window-navigator.html

js 主要需要修改浏览器的 window.navigator.webdriver、window.navigator.languages等值。

打开正常的浏览器可以看到:

window.navigator.webdriver的值为undefined,而通过pyppeteer控制打开的浏览器该值为True,当被检测到该值为True的时候,则滑动会一直失败,所以我们需要修改该属性。需要注意,在测试的过程中发现登陆成功后页面的该属性又会变成True,所以在每次重新加载页面后要重新设置该属性的值。

async def page_evaluate(page):# 替换淘宝在检测浏览时采集的一些参数await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')

另一种方法可以进一步免去淘宝登录的烦恼,那就是设置用户目录。

平时我们已经注意到,当我们登录淘宝之后,如果下次再次打开浏览器发现还是登录的状态。这是因为淘宝的一些关键Cookies已经保存到本地了,下次登录的时候可以直接读取并保持登录状态。

那么这些信息保存在哪里了呢?其实就是保存在用户目录下了,里面不仅包含了浏览器的基本配置信息,还有一些Cache、Cookies等各种信息都在里面,如果我们能在浏览器启动的时候读取这些信息,那么启动的时候就可以恢复一些历史记录甚至一些登录状态信息了。

这也就解决了一个问题:很多朋友在每次启动 Selenium 或 Pyppeteer 的时候总是是一个全新的浏览器,那就是没有设置用户目录,如果设置了它,每次打开就不再是一个全新的浏览器了,它可以恢复之前的历史记录,也可以恢复很多网站的登录信息。

当然可能时间太久了,Cookies 都过期了,那还是需要登录的。

那么这个怎么来做呢?很简单,在启动的时候设置 userDataDir 就好了,示例如下:

 browser = await launch(headless=False,userDataDir='./userdata',args=['--disable-infobars', f'--window-size={width},{height}'])

好,这里就是加了一个 userDataDir 的属性,值为 userdata,即当前目录的 userdata 文件夹。我们可以首先运行一下,然后登录一次淘宝,这时候我们同时可以观察到在当前运行目录下又多了一个 userdata 的文件夹:

用户文件夹

具体的介绍可以看官方的一些说明,如:https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md 这里面介绍了 userdatadir 的相关内容。

 

命令行启动 chrome 并进入指定的 URL:chrome.exe --disable-infobars --user-data-dir="./userdatadir" --new-window https://login.taobao.com/member/login.jhtml

执行完后会打开 淘宝的登录页面,登录淘宝,然后保存用户名密码,这样登录信息就保存在 userdatadir 目录下了

在执行 chrome.exe --disable-infobars --user-data-dir="./userdatadir" --new-window https://www.taobao.com

可以看到已经时登录状态了。

示例 2 :爬取今日头条


# -*- coding: utf-8 -*-
# @Author  : 
# @File    : toutiao.py
# @Software: PyCharm
# @description : XXXimport asyncio
from pyppeteer import launch
from pyquery import PyQuery as pqdef screen_size():"""使用tkinter获取屏幕大小"""import tkintertk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return width, heightasync def main():width, heigth = screen_size()print(f'screen : [width:{width}, height:{height} ]')browser = await launch(headless=False, args=[f'--window-size={width},{height}'])page = await browser.newPage()await page.setViewport({'width': width, 'height': height})# 是否启用JS, enabled设为False,则无渲染结果await page.setJavaScriptEnabled(enabled=True)await page.goto('https://www.toutiao.com')await asyncio.sleep(5)print(await page.cookies()) # 打印页面cookiesprint(await page.content()) # 打印页面文本print(await page.title())  # 打印当前页标题# 抓取新闻标题title_elements = await page.xpath('//div[@class="title-box"]/a')for item in title_elements:# 获取文本title_str = await (await item.getProperty('textContent')).jsonValue()print(await item.getProperty('textContent'))# 获取链接title_link = await (await item.getProperty('href')).jsonValue()print(title_str)print(title_link)# 在搜索框中输入pythonawait page.type(input.tt-input__inner', 'python')# 点击搜索按钮await page.click('button.tt-button')await asyncio.sleep(5)# print(page.url)# 今日头条点击后新开一个页面,通过打印url可以看出page还停留在原页面# 以下用于切换至新页面pages = await browser.pages()page = pages[-1]# print(page.url)page_source = await page.content()text = pq(page_source)await page.goto(url="https://www.toutiao.com/api/search/content/?""aid=24&app_name=web_search&offset=60&format=json""&keyword=python&autoload=true&count=20&en_qc=1""&cur_tab=1&from=search_tab&pd=synthesis&timestamp=1555589585193")for i in range(1, 10):print(text("#J_section_{} > div > div > div.normal.rbox > div > div.title-box > a > span".format(i)).text())# 关闭浏览器await browser.close()asyncio.get_event_loop().run_until_complete(main())

示例代码2:

import asyncio
from pyppeteer import launchasync def main():# headless参数设为False,则变成有头模式browser = await launch(# headless=False)page = await browser.newPage()# 设置页面视图大小await page.setViewport(viewport={'width': 1280, 'height': 800})# 是否启用JS,enabled设为False,则无渲染效果await page.setJavaScriptEnabled(enabled=True)await page.goto('https://www.toutiao.com/')# 打印页面cookiesprint(await page.cookies())# 打印页面文本print(await page.content())# 打印当前页标题print(await page.title())# 抓取新闻标题title_elements = await page.xpath('//div[@class="title-box"]/a')for item in title_elements:# 获取文本title_str = await (await item.getProperty('textContent')).jsonValue()print(await item.getProperty('textContent'))# 获取链接title_link = await (await item.getProperty('href')).jsonValue()print(title_str)print(title_link)# 关闭浏览器await browser.close()asyncio.get_event_loop().run_until_complete(main())

百度首页交互

示例代码:

import time
import asyncio
from pyppeteer import launchasync def main():browser = await launch(headless=False)page = await browser.newPage()await page.setViewport({'width': 1200, 'height': 800})await page.goto('https://www.baidu.com')# 在搜索框中输入pythonawait page.type('input#kw.s_ipt', 'python')# 点击搜索按钮await page.click('input#su')# 等待元素加载,第一种办法,强行等待5秒# await asyncio.sleep(5)# 第二种方法,在while循环里强行查询某元素进行等待while not await page.querySelector('.t'):pass# 滚动到页面底部await page.evaluate('window.scrollBy(0, window.innerHeight)')# 这些等待方法都不好用# await page.waitForXPath('h3', timeout=300)# await page.waitForNavigation(waitUntil="networkidle0")# await page.waitForFunction('document.getElementByTag("h3")')# await page.waitForSelector('.t')# await page.waitFor('document.querySelector("#t")')# await page.waitForNavigation(waitUntil='networkidle0')# await page.waitForFunction('document.querySelector("").inner‌​Text.length == 7')title_elements = await page.xpath('//h3[contains(@class, "t")]/a')for item in title_elements:title_str = await (await item.getProperty('textContent')).jsonValue()print(title_str)await browser.close()asyncio.get_event_loop().run_until_complete(main())

示例:

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 学习笔记(7):Java面试Offer直通车-从抽象类和接口角度展示面向对象方面能力

    立即学习:https://edu.csdn.net/course/play/27126/355507?utm_source=blogtoedu抽象类和接口的语法有抽象方法的必须是抽象类,反之不然;抽象方法不能定义方法体子类继承抽象方法时,必须实现抽象方法 接口相关的语法接口的方法没有方法体一个类可以实现多个接口实现接口的类…...

    2024/5/1 8:00:16
  2. JWT框架简单测评,哪款是你的菜

    序温故而知新,可以为师矣。JWT的实现框架 从上一篇 [JWT就是这么简单](<https://blog.csdn.net/Ajava666/article/details/107970565>) 知道JWT是一种标准,而不是具体的实现,那么在JAVA中实现了JWT的框架多不胜数(公司内部自己写的JWT框架)。官方推荐是使用官方的Auth…...

    2024/4/17 19:22:26
  3. js中renturn与break和continue的区别

    3个关键词的含义和比较在 break,continue和return 三个关键字中, break,continue是化为一类的,return 是函数返回语句,但是返回的同时也将函数停止。相同之处:三个都会将此时进行的语句停止。不同之处:1、break:是立即结束语句,并跳出语句,进行下个语句执行。2、contin…...

    2024/4/22 10:48:06
  4. MyBatis-Plus分页查询及动态sql处理

    导入依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifa…...

    2024/4/28 0:58:29
  5. 第六十六周学习生活总结

    今天是2020年8月24日,周一,昨天又拖更了,所以今天一直提醒自己要把昨天的更新给补上,所以,补档来了。一个好消息,一个坏消息。先说坏消息,我奶奶昨天晚上半夜又生病住院了,还是原来的老毛病,心脏不好。记得今年六月份的时候奶奶就已经生病住了一次院,那次我爸妈比较忙…...

    2024/5/1 7:23:59
  6. 过孔滑环使用条件详细讲解分析

    导电滑环是一种机械连接转动部件,在机械设备中起着非常重要的作用,其质量的好坏严重影响整个设备的运行,所以,判断导电滑环质量的好坏是十分重要的。但是在大多数情况下,由于滑环不便拆卸,用户收到货时无法通过查看内部材质判断其质量。如果擅自拆卸,可能会影响导电滑环…...

    2024/4/27 18:19:25
  7. Java-springboot生鲜电商项目(五)购物车模块

    Java-springboot生鲜电商项目(五)购物车模块购物车功能涉及到的接口,购物车模块(都是前台的)业务流程总结常见错误(一)购物车列表daomapperservice(二)添加商品到购物车对用户的过滤器开发:因为购物车的功能是用户的行为操作,所以在添加商品到购物车的时候,先判断是…...

    2024/4/18 9:21:32
  8. web 文件上传漏洞

    转载 https://www.cnblogs.com/YGblood/p/10443600.html1.目标网站具有上传功能上传攻击的前提是:目标网站具有上传功能,可以上传文件,并且上传文件,并且文件上传到服务器能被存储。2.上传的目标文件能够被Web服务器解析执行由于上传文件需要依靠中间件解析执行,因此上传文…...

    2024/4/23 6:37:54
  9. a too low setting for -Xss and illegal cyclic inheritance dependencies.

    tomcat日志:ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) at or…...

    2024/4/27 18:26:45
  10. java 文件下载跨域问题

    response.reset(); response.setContentType(“application/octet-stream; charset=utf-8”); response.addHeader(“Access-Control-Allow-Origin”, httpServletRequest.getHeader(“Origin”)); response.addHeader(“Access-Control-Expose-Headers”,“token,uid,Content-…...

    2024/4/11 21:04:34
  11. [2019CCPC-江西省赛] D - Wave 暴力/dp

    题目链接:D - Wave 题意 给你一个长度为n的字符串,字符串只包含1~c数字,让你找一个子字符串要求子字符串的奇数位为一个数,偶数位为一个数并且奇数位和偶数位不同。 题解 本题有一个关键点c≤100,很明显我们可以通过枚举奇数位和偶数位的数字来得到答案。当奇数位为i,偶…...

    2024/4/30 8:43:09
  12. Java网络编程 -- BIO 阻塞式网络编程

    阻塞IO的含义 阻塞(blocking)IO :阻塞是指结果返回之前,线程会被挂起,函数只有在得到结果之后(或超时)才会返回 非阻塞(non-blocking)IO :非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回 同步(synchronous)IO :应用阻…...

    2024/4/11 21:04:33
  13. Apache开启 目录浏览 功能

    Apache配置支持目录浏览主配置文件 httpd.conf 中修改:在配置文件那里添加如下内容12345678910Directory "文件绝对路径">#开启目录列表索引模式Options Indexes#排序先允许allow再denyOrder allow,deny#设置字符集,以消除中文乱码;指定目录列表可以显示最长为2…...

    2024/4/30 7:43:37
  14. Java-springboot生鲜电商项目(六)订单模块

    Java-springboot生鲜电商项目(六)订单模块(爆炸难)订单开发思路涉及到的接口重难点(一)创建订单新建一个创建订单的请求类添加异常在Constant添加在service添加创建订单方法controller实现在postman进行测试(二)订单详情定义异常先在dao创建接口orderMpperMapper先在da…...

    2024/4/28 14:00:17
  15. LeetCode刷题(93)~寻找数组的中心索引

    题目描述 给定一个整数类型的数组 nums,请编写一个能够返回数组 “中心索引” 的方法。 我们是这样定义数组 中心索引 的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。 如果数组不存在中心索引,那么我们应该返回 -1。如果数组有多个中心索引,那么我们应该…...

    2024/4/9 21:49:39
  16. html 速查词典

    html 速查词典 http://www.w3cschool.cn/html/dict...

    2024/4/10 11:30:20
  17. SpringBoot+Dubbo(XML常用配置)

    SpringBoot+Dubbo(XML常用配置)客户端访问超时,在客户端的配置文件中增加超时配置 <dubbo:consumer timeout="180000" retries="3" /> 启动客户端时报错,8080端口被占用,修改配置文件application.properties中默认的Tomcat端口 server.port=808…...

    2024/4/10 8:59:18
  18. Appium参数

    ...

    2024/4/10 11:30:18
  19. Java按照对象属性排序

    *** 排序* @date 2020/8/20*/ public class PaiXU {public static void main(String[] args) {List<User> list = new ArrayList<>();User user=new User();user.setAge(18);user.setId(1);user.setName("a");User user1=new User();user1.setAge(13);us…...

    2024/4/10 11:30:17
  20. 委托

    委托 委托(delegate)是一种知道如何调用方法的对象。 委托类型(delegate type)定义了一种委托实例(delegate instance)可以定义的方法。具体来说,它定义了方法的返回类型(return type)和参数类型(parameter type)。以下语句定义了一个委托类型 Transformer:定义委托…...

    2024/4/29 9:58:02

最新文章

  1. 017、Python+fastapi,第一个Python项目走向第17步:ubuntu24.04 无界面服务器版下安装nvidia显卡驱动

    一、说明 新的ubuntu24.04正式版发布了&#xff0c;前段时间玩了下桌面版&#xff0c;感觉还行&#xff0c;先安装一个服务器无界面版本吧 安装时有一个openssh选择安装&#xff0c;要不然就不能ssh远程&#xff0c;我就是没选&#xff0c;后来重新安装ssh。 另外一个就是安…...

    2024/5/1 9:06:47
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. dp小兰走迷宫

    昨天学习了bfs的基本概念&#xff0c;今天来做一道经典习题练练手吧&#xff01; bfs常用的两类题型 1.从A出发是否存在到达B的路径(dfs也可) 2.从A出发到B的最短路径&#xff08;数小:<20才能用dfs&#xff09; 遗留的那个问题的答案- 题目&#xff1a;走迷宫 #incl…...

    2024/5/1 8:48:43
  4. ADB(Android Debug Bridge)操作命令详解及示例

    ADB&#xff08;Android Debug Bridge&#xff09;是一个强大的命令行工具&#xff0c;它是Android SDK的一部分&#xff0c;主要用于Android设备&#xff08;包括真实手机和平板电脑以及模拟器&#xff09;的调试、系统控制和应用程序部署。 下面是一些ADB的常用命令&#xff…...

    2024/4/30 1:22:14
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/4/30 9:36:27
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/4/30 0:57:52
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/4/29 18:43:42
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/1 4:07:45
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/4/30 23:32:22
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/4/30 23:16:16
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/1 6:35:25
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/4/29 21:25:29
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/1 4:35:02
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/4/30 14:53:47
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/4/30 22:14:26
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/1 6:34:45
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/4/30 22:57:18
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/4/30 20:39:53
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/1 4:45:02
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/1 8:32:56
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/4/29 3:42:58
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/4/29 19:56:39
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/1 5:23:20
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/4/30 20:52:33
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57