121.4-python-selenium进阶元素定位和一个小项目


@[toc]

前言

最近参加了一个信息类的比赛,主办方提供了数据库和题库,正好借此练习爬虫。

selenium不同于其他py爬虫包,它是借助浏览器控制器1直接模拟人进行操作,这也造成selenium必须考虑网页加载和元素定位的问题。

此次项目主要涉及selenium进行网页元素定位的新知识,包括css定位、xpath定位、js定位等。

​ 元素特征明显可直接复制xpath进行定位,特征不明显的建议使用css_selector。

selenium还支持导入js帮助进行网页操作,此文不涉及。

背景

尝试使用requests爬取,但是获取题库的参数比较复杂懒得进行研究,于是选择selenium进行傻瓜式爬取。

代码实现

imports:

1
2
3
4
5
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

QUES_POOL:

1
2
with open("testpool.txt","a+",encoding="utf-8") as f:
    f.write("这是个题库!")  # 自带文件关闭功能,不需要再写f.close()

配置控制器:

1
2
3
4
5
6
7
8
9

user_agent = "Mozilla/5.0 ******"
opt = webdriver.ChromeOptions()
opt.add_argument('--user-agent=%s' % user_agent)

browser = webdriver.Chrome(r'D:\chromedriver.exe',options=opt)
browser.get('url')   #进入网站
browser.maximize_window()	#全屏
browser.implicitly_wait(5)	#等待加载

通过class_name定位:

1
2
3
element = browser.find_element(By.CLASS_NAME,"input-phone")	#找到class为input-phone的元素。
element.clear()
element.send_keys("WORDS")

通过XPATH定位,并且对一系列元素进行操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
counti = 1
while counti<13:
    iii = str(counti)
    element = browser.find_element(
        By.XPATH,
        '//*[@id="components-layout-demo-custom-trigger"]/section/main/div/div/div/div[2]/div/div[3]/div[2]/div[2]/div/div['
        + iii+']/div'	
        )	#这一排XPATH通过对div序号的更改定位了一系列的元素
    print(element.text,counti)
    element.click()
    counti+=1
sleep(1) 	#为了给元素进行翻页的时间,以保障稳定性。

此外,页面缩放往往对密集元素的定位造成影响,所以尽量不要在运行途中操作页面和鼠标,这有使程序报错的风险。

### 对下拉栏、combobox的操作
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
inputnandu =browser.find_element(By.XPATH,'//*[@id="components-layout-demo-custom-trigger"]/section/main/div/div/div/div[3]/div/div/div[6]/div/div/ul/li/div/input')
inputnandu.click()#试题难度
inputnandu.send_keys('简单')
inputnandu.send_keys(Keys.ENTER)
inputnandu.click()
inputnandu.send_keys('困难')
inputnandu.send_keys(Keys.ARROW_UP)
inputnandu.send_keys(Keys.ENTER)
inputnandu.send_keys('中等')
inputnandu.send_keys(Keys.ARROW_UP)
browser.implicitly_wait(1)
inputnandu.send_keys(Keys.ENTER)
sleep(1)

有的下拉栏能够输入,以此帮助选择栏目,此类推荐定位到input元素。

无input元素的尝试挑几个元素click( ),然后向元素发送键盘指令,比如up-arrow、enter。

注意:带input的运行可以忽略加载时间,而没有input的必须考虑下拉栏加载时间。页面有加载动画的,必须考虑元素加载时间。

非alert的html弹窗

1
2
3
4
5
6
7
slalbel = browser.find_element(By.XPATH,'//*[@id="components-layout-demo-custom-trigger"]/section/main/div/div/div/div[3]/div/div/div[7]')
slalbel.click()	##点击
sleep(1)	#加载时间
elements = browser.find_elements(By.CLASS_NAME,"item")
btn = browser.find_elements(By.CLASS_NAME,'btns')
print(elements[4].text,btn[0].text)	#加载的内容
ActionChains(browser).click(elements[4]).click(btn[0]).perform()

如果考虑了弹窗的加载时间,那么直接使用XPATH进行定位元素。

有的元素需要长按拖动等复杂的一系列连续操作,可以尝试使用ActionChains,这里略。

奇葩的无法定位元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
hands=browser.window_handles
browser.switch_to.window(hands[-1])	#方法一:检查窗口,是不是有新页面、ifram等

idren = browser.find_element(By.CSS_SELECTOR,'body > div:nth-child(11) > div > div.ant-modal-wrap.ant-modal-centered.ant-modal-confirm-centered > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:nth-child(1)')	#方法二:使用css_selector进行定位
idren.text #'仍要交卷'
idren.send_keys(Keys.ENTER)
sleep(5)	#方法三:给予充足的加载时间
chakan = browser.find_element(By.CSS_SELECTOR,'body > div:nth-child(11) > div > div.ant-modal-wrap.ant-modal-centered.ant-modal-confirm-centered > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button.ant-btn.ant-btn-primary')
chakan.text #看详情'
chakan.send_keys(Keys.ENTER)

使用这三个方法,我遇到的问题得到了解决。

最后


我推荐使用IDLE进行调试,而不是单独使用VScode。

展望

调整或调试程序要目的明确并且有序。

要区分测试和成品。

CTRL-/