search.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. """步骤:搜索关键词 / 视频筛选 / 打开首个视频。"""
  2. from __future__ import annotations
  3. import random
  4. from urllib.parse import quote
  5. from playwright.sync_api import Page
  6. from collectors.douyin.common import human_pause
  7. def search_keyword(page: Page, keyword: str) -> None:
  8. search = page.get_by_placeholder("搜索你感兴趣的内容").or_(
  9. page.locator('input[type="search"], input[enterkeyhint="search"]').first
  10. ).first
  11. search.wait_for(state="visible", timeout=15_000)
  12. human_pause(0.8, 1.6)
  13. search.click()
  14. human_pause(0.5, 1.2)
  15. search.fill("")
  16. human_pause(0.3, 0.8)
  17. search.press_sequentially(keyword, delay=random.randint(80, 180))
  18. print(f"已输入关键词: {keyword}")
  19. human_pause(1.2, 2.5)
  20. search.press("Enter")
  21. page.wait_for_load_state("domcontentloaded")
  22. print(f"已搜索关键词: {keyword}")
  23. def click_video_filter(page: Page, keyword: str) -> None:
  24. page.wait_for_function(
  25. """() => {
  26. const spans = Array.from(document.querySelectorAll('span'));
  27. return spans.some(s => {
  28. const t = (s.innerText || '').trim();
  29. const y = s.getBoundingClientRect().y;
  30. return t === '视频' && y > 40 && y < 120;
  31. });
  32. }""",
  33. timeout=20_000,
  34. )
  35. human_pause(0.8, 1.6)
  36. clicked = page.evaluate(
  37. """() => {
  38. const spans = Array.from(document.querySelectorAll('span'));
  39. const el = spans.find(s => {
  40. const t = (s.innerText || '').trim();
  41. const rect = s.getBoundingClientRect();
  42. return t === '视频' && rect.width > 0 && rect.y > 40 && rect.y < 120;
  43. });
  44. if (!el) return false;
  45. el.click();
  46. return true;
  47. }"""
  48. )
  49. if not clicked:
  50. url = f"https://www.douyin.com/search/{quote(keyword)}?type=video"
  51. print(f"未点到「视频」栏,改为直接打开: {url}")
  52. page.goto(url, wait_until="domcontentloaded")
  53. else:
  54. print("已点击顶部「视频」筛选项")
  55. page.wait_for_load_state("domcontentloaded")
  56. human_pause(2.5, 4.0)
  57. def open_first_video(page: Page) -> None:
  58. page.wait_for_selector('a[href*="/video/"]', timeout=20_000)
  59. human_pause(1.0, 2.0)
  60. first_video = page.locator('a[href*="/video/"]:visible').first
  61. first_video.wait_for(state="visible", timeout=10_000)
  62. href = first_video.get_attribute("href") or ""
  63. print(f"准备打开第一个视频: {href}")
  64. human_pause(0.8, 1.5)
  65. try:
  66. first_video.click(timeout=5_000)
  67. except Exception:
  68. print("普通点击失败,改为 JS 点击第一个视频")
  69. page.evaluate(
  70. """() => {
  71. const a = document.querySelector('a[href*="/video/"]');
  72. if (a) a.click();
  73. }"""
  74. )
  75. page.wait_for_load_state("domcontentloaded")
  76. print(f"已进入视频页: {page.url}")