Я пытаюсь выполнить поиск в Google с помощью драматурга. Но получаю эту ошибку:
playwright._impl._errors.TimeoutError: Page.fill: Timeout 60000ms exceeded.
Call log:
waiting for locator("input[name=\"q\"]")
Вот код:
from playwright.async_api import async_playwright
import asyncio
async def main():
async with async_playwright() as pw:
browser = await pw.chromium.launch(args=["--disable-gpu", "--single-process", "--headless=new"], headless=True)
page = await browser.new_page()
# Go to Google
await page.goto('https://www.google.com')
# Accept the cookies prompt (if it appears)
try:
accept_button = await page.wait_for_selector('button:has-text("I agree")', timeout=5000)
if accept_button:
await accept_button.click()
except:
pass
# Search for a query
query = "Playwright Python"
await page.fill('input[name = "q"]', query, timeout=60000)
await page.press('input[name = "q"]', 'Enter')
# Wait for the results to load
await page.wait_for_selector('h3')
# Extract the first result's link
first_result = await page.query_selector('h3')
first_link = await first_result.evaluate('(element) => element.closest("a").href')
print("First search result link:", first_link)
await browser.close()
if __name__ == '__main__':
asyncio.run(main())
Этот элемент не input
, а textarea
Как упоминалось в комментарии , замена input
на textarea
решает проблему.
Тем не менее, распространенная XY-проблема/антипаттерн в парсинге предполагает, что вы должны действовать как человек. Это касается только тестирования. При парсинге вы можете использовать ярлыки, которые позволят получить результат быстрее, надежнее и с меньшим количеством кода. Пропускайте посторонние страницы, не нажимайте кнопки без необходимости, удаляйте баннеры cookie вместо того, чтобы покорно их принимать, пропускайте проверки видимости и доверенные события. Вы даже можете перехватывать запросы или напрямую обращаться к API.
Применив это на практике, вы можете перейти непосредственно к странице результатов с помощью одной навигации и покончить с этим, избегая суеты, медлительности и ненадежности автоматизации целевой страницы:
import asyncio
import urllib.parse
from playwright.async_api import async_playwright # 1.44.0
async def main():
term = urllib.parse.quote_plus("playwright python")
url = f"https://www.google.com/search?q = {term}"
async with async_playwright() as pw:
browser = await pw.chromium.launch()
page = await browser.new_page()
await page.goto(url, wait_until = "domcontentloaded")
link = await page.locator("h3").first.evaluate('el => el.closest("a").href')
print("First search result link:", link)
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
Избегайте wait_for_selector
и query_selector
— отдайте предпочтение локаторам.
Кроме того, данные находятся в статическом HTML-коде, так что вам даже не понадобится Playwright, если вам удобно немного обрабатывать URL-адреса (Google по какой-то причине запутывает результаты):
import re
import urllib.parse
from bs4 import BeautifulSoup # 4.10.0
from requests import get # 2.31.0
term = urllib.parse.quote_plus("playwright python")
response = get(f"https://www.google.com/search?q = {term}")
response.raise_for_status()
soup = BeautifulSoup(response.text, "lxml") # 4.8.0
link = soup.select_one("h3").find_parent("a")["href"].replace(r"/url?q = ", "")
link = re.sub(r"&sa=U&.*", "", link)
print("First search result link:", link)
Тест скорости:
# OP's playwright script after the input -> textarea fix
real 0m7.487s
user 0m2.804s
sys 0m0.438s
# my playwright script
real 0m1.046s
user 0m0.539s
sys 0m0.136s
# requests/beautiful soup
real 0m0.521s
user 0m0.157s
sys 0m0.023s
В некоторых случаях может быть полезно заблокировать запросы к ненужным вам ресурсам, таким как изображения, таблицы стилей и т. д., и отключить JS. Вот пример того, как это сделать для потомков, но в данном случае это не поможет, вероятно, потому, что загрузка Google довольно быстрая и JS-light уже:
import asyncio
import urllib.parse
from playwright.async_api import async_playwright
async def main():
term = urllib.parse.quote_plus("playwright python")
url = f"https://www.google.com/search?q = {term}"
async def handle_requests(route, request):
if request.url.startswith(url):
await route.continue_()
else:
await route.abort()
async with async_playwright() as pw:
browser = await pw.chromium.launch()
context = await browser.new_context(java_script_enabled=False)
page = await context.new_page()
await page.route("**/*", handle_requests)
await page.goto(url, wait_until = "domcontentloaded")
link = await page.locator("h3").first.evaluate('el => el.closest("a").href')
print("First search result link:", link)
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
Зачем полагаться на автоматизацию главной страницы, если можно сразу перейти к результатам?
page.goto("https://www.google.com/search?q=playwright+python", wait_until = "commit")
.