这里通过一段示例代码来描述如何使用 Python 的 puppeteer binding 库 pyppeteer
。
import asyncio
from pyppeteer import launch
async def main():
# 启动 Headless Chrome,需要带 `--no-sandbox` 参数,不然会报错
# 具体原因不详,参考 https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md
browser = await launch({'headless': True, 'args': ['--no-sandbox']})
page = await browser.newPage()
# 注意,不带 headless 参数时,实时的 viewport 大小并不是这个值,可能受各系统 DPI 参数 / UI 缩放等影响
await page.setViewport({"width": 1366, "height": 768})
for enterprise in Enterprise.select().where(Enterprise.status == 'pending'):
print(f"Running {enterprise.name}")
# 打开网页
await page.goto('https://www.szcredit.org.cn/web/index.html')
# 聚焦
await page.focus('input[name="txtKeyword"]')
# 输入
await page.type('input[name="txtKeyword"]', enterprise.name)
# 点击按钮
await page.click('#btnSend')
# 由于点完按钮会发 AJAX 请求显示验证码,这里强行等 2 秒
await page.waitFor(2000)
# 由于 headless 和非 headless 模式下 viewport 不一,为了调试,只好弄两套 clip 参数
headless_clip = {'x': 550, 'y': 250, 'width': 320, 'height': 175}
not_headless_clip = {'x': 550, 'y': 250, 'width': 320, 'height': 175}
clip = headless_clip if HEADLESS else not_headless_clip
# 截图,即可截全图、滚动截图(加上参数 fullPage: True),也可只截一块;保存在 code.png 上
# WARNING: 这段代码是为了截验证码图片,但它不是好的实践。参考 wiki 中截取图片的内容
await page.screenshot({'path': 'code.png', 'clip': clip})
code = input("Verify Code: ")
# 网页用了 iframe,从 frame 列表中找到你要的那个
verify_code_frame = [f for f in page.frames if f.url.endswith('/web/GSPT/ShowCheckCode.aspx')][0]
await verify_code_frame.focus('#txtCheckCode')
await verify_code_frame.type('#txtCheckCode', code)
await page.click('.layui-layer-btn0')
# 点上面按钮后会有新 tab 弹出,等待加载完成
await page.waitForNavigation()
# 等待特定的 DOM 元素出现,但是效果似乎不是想象中的
await page.waitForSelector('#result', {'visible': True})
await page.waitFor(2000)
# 这段代码演示如何从网页结构中提取数据,比较纠结
anchors = await page.querySelectorAll("#result a")
for anchor in anchors:
info = await page.evaluate('(anchor) => Object({"href": anchor.href, "text": anchor.innerText})', anchor)
if info['text'] == enterprise.name:
enterprise.sz_credit_url = info['href']
enterprise.status = 'success'
print(f"URL of {enterprise.name} saved: {enterprise.sz_credit_url}")
break
else:
enterprise.status = 'skipped'
enterprise.save()
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
判断某一 xpath 在页面中是否存在:
anchors = await page.xpath(f'//a[text()="股东登记信息"]')
if anchors:
print("Exists")
else:
print("Not exists")