121.4-python-selenium进阶元素定位和一个小项目
@[toc]
最近参加了一个信息类的比赛,主办方提供了数据库和题库,正好借此练习爬虫。
selenium不同于其他py爬虫包,它是借助浏览器控制器1直接模拟人进行操作,这也造成selenium必须考虑网页加载和元素定位的问题。
此次项目主要涉及selenium进行网页元素定位的新知识,包括css定位、xpath定位、js定位等。
元素特征明显可直接复制xpath进行定位,特征不明显的建议使用css_selector。
selenium还支持导入js帮助进行网页操作,此文不涉及。
尝试使用requests爬取,但是获取题库的参数比较复杂懒得进行研究,于是选择selenium进行傻瓜式爬取。
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
|
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) #等待加载
|
1
2
3
| element = browser.find_element(By.CLASS_NAME,"input-phone") #找到class为input-phone的元素。
element.clear()
element.send_keys("WORDS")
|
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的必须考虑下拉栏加载时间。页面有加载动画的,必须考虑元素加载时间。
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。
调整或调试程序要目的明确并且有序。
要区分测试和成品。