首页 > 解决方案 > Python Selenium Webdriver - 删除 Facebook 帖子时无法找到元素

问题描述

我正在编写一个 Python 脚本来帮助我使用 Selenium Webdriver 删除多余的 facebook 群组帖子,但我遇到了 Selenium 无法定位元素的问题。

我得到的错误是:

selenium.common.exceptions.NoSuchElementException: 
Message: no such element: Unable to locate element: 
{"method":"xpath","selector":"//*[@id="post_menu"]/div/ul/li[10]/a"}

我的代码如下所示:

import os
import string
import time
import requests
import config
import re
import random
from tinytag import TinyTag
from clint.textui import progress
from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

browser = webdriver.Chrome()
browser.implicitly_wait(60)

browser.get("https://www.facebook.com/groups/group_id/yourposts/?availability=available&referral_surface=your_posts_unsold_notif")
browser.maximize_window()
time.sleep(3)

browser.find_element_by_id("email").send_keys("email")
browser.find_element_by_id("pass").send_keys("password")
print("Logging in ...")

browser.find_element_by_id("loginbutton").click()
print("Logged in ...")

mainWindowHandle = browser.window_handles
print "main window handle: %s" %mainWindowHandle

elements = browser.find_elements_by_xpath('//*[contains(@id, "mall_post_")]')
for element in elements:
  allWindowsHandlesList = browser.window_handles
  print "all window handles: %s" %allWindowsHandlesList

  id = element.get_attribute("id")[10:]
  link_x_path = "//*[@id='mall_post_%s']/div/div[1]/a" % (id)
  link = browser.find_element_by_xpath(link_x_path)
  actions = ActionChains(browser)
  actions.move_to_element(link).perform()

  time.sleep(4)
  link.click()

  delete = browser.find_element_by_xpath('//*[@id="post_menu"]/div/ul/li[10]/a')
  delete.click()

当我尝试找到可能由 Javascript 加载的删除链接时,会出现问题:

delete = browser.find_element_by_xpath('//*[@id="post_menu"]/div/ul/li[10]/a')

这是包含链接的 li,我通过从 Chrome 检查器复制链接来获取 Xpath,有一个复制 Xpath 的选项。

<li class="_54ni _41t6 __MenuItem" role="presentation">
<a class="_54nc" href="#" rel="async-post"
ajaxify="/ajax/groups/mall/delete/?group_id=874536857643876&amp;post_id=7836284732687326&amp;story_dom_id=u_fetchstream_3_o&amp;entstory_context=%7B%22last_view_time%22%3A1532623110%2C%22fbfeed_context%22%3Atrue%2C%22location_type%22%3A3%2C%22outer_object_element_id%22%3A%22u_fetchstream_3_o%22%2C%22object_element_id%22%3A%22u_fetchstream_3_o%22%2C%22is_ad_preview%22%3Afalse%2C%22is_editable%22%3Afalse%2C%22mall_how_many_post_comments%22%3A2%2C%22bump_reason%22%3A0%2C%22enable_comment%22%3Afalse%2C%22story_width%22%3A502%2C%22tn-str%22%3A%22-R%22%7D&amp;surface=group_post_chevron&amp;location=3" role="menuitem">
<span><span class="_54nh">
<div class="_41t5">
<i class="_41t7 img sp_PBbYkTGVdjY_2x sx_92b175"></i>
<i class="_41t8 img sp_4Wahr7NwMMo_2x sx_7864af"></i>
Delete post</div></span></span></a>
</li>

点击上述链接后,会打开一个弹出窗口,询问您是否确定要删除帖子,这是需要点击的删除按钮:

<button value="1" class="_42ft _4jy0 layerConfirm uiOverlayButton _4jy3 _4jy1 selected _51sy" data-testid="delete_post_confirm_button" type="submit">Delete</button>

链接如下所示:

facebook删除帖子链接

Google Chrome Inspector 中的代码如下所示:

Google Chrome Inspector 删除帖子链接代码

任何帮助表示赞赏!干杯!

标签: pythonseleniumselenium-webdriver

解决方案


您似乎是importing WebDriverWait,但没有使用它。如果您在脚本中包含正确的等待条件,并替换您的time.sleep()调用,您将拥有一个更加一致和有效的selenium 脚本。

这是使用上面代码的示例:

注意:此代码未经测试,并且是在 Python 3 中构建的,您似乎使用的是 Python 2,但它仍应按原样工作。

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

browser = webdriver.Chrome()
wait = WebDriverWait(browser, 10)

browser.get("https://www.facebook.com/groups/group_id/yourposts/?availability=available&referral_surface=your_posts_unsold_notif")
browser.maximize_window()

wait.until(EC.visibility_of_element_located((By.ID, 'email'))).send_keys("email")
wait.until(EC.visibility_of_element_located((By.ID, 'pass'))).send_keys("password")
wait.until(EC.element_to_be_clickable((By.ID, 'loginbutton'))).click()
print("Logged in ...")

mainWindowHandle = browser.window_handles
print ("main window handle: %s" %mainWindowHandle)

elements = wait.until(EC.visibility_of_all_elements_located((By.XPATH, '//*[contains(@id, "mall_post_")]')))
for element in elements:
    allWindowsHandlesList = browser.window_handles
    print ("all window handles: %s" %allWindowsHandlesList)

    element_id = element.get_attribute("id")[10:]
    link_x_path = "//*[@id='mall_post_%s']/div/div[1]/a" % element_id
    link = wait.until(EC.visibility_of_element_located((By.XPATH, link_x_path)))
    actions = ActionChains(browser)
    actions.move_to_element(link).perform()
    wait.until(EC.element_to_be_clickable((By.XPATH, link_x_path))).click()

    #the wait here should resolve the AJAX load issue that caused your element to not be found    
    wait.until(EC.element_to_be_clickable((By.XPATH, '//div[@class="uiContextualLayerPositioner uiLayer"]/div/div[@id="post_menu"]/div/ul/li[10]/a'))).click()

只要您的所有定位器都是正确的,您现在应该能够单击删除按钮。


推荐阅读