Python+selenium 模拟网页点击爬虫车辆定位系统

Posted 微信公众号:您好啊数模君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python+selenium 模拟网页点击爬虫车辆定位系统相关的知识,希望对你有一定的参考价值。

在上一篇文章《Python教程—模拟网页点击》讲解了简单的登录过程,本次讲一下完整的selenium爬虫,依然针对车辆定位系统这类网址,这类网址有个特点就是需要点击触发才能获取动态数据,反应时间看网速,也容易漏掉部分数据,并且访问元素在列表中,不能直接使用Copy Xpath的路径,需要先访问列表块,再去访问其中的元素,甚至还有要先访问列表图块才能对其中的元素进行访问。

一般网页版客户端不好用还不得不用,本文分享的内容希望能帮助同行解放双手,一个是无浏览器页面,一个是有浏览器页面,可以看下具体效果。

主要的库有selenium和time,其中keys主要使用其中的回车功能

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

将数据保存至csv中,csv比xlsx读写数据速率更快,并且以当前时间作为文件名,需要用到额外的库有

import csv
import datetime

设置time.sleep()等待点击或读取数据,数据窗口弹出快慢不定,那么我们可以将

time.sleep(1)     #加载等待
driver.find_element_by_xpath("").click()#点击
time.sleep(1)     #加载等待
driver.find_element_by_xpath("").text#读取文本

替换为智能等待语句

WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,""))).click()#点击
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,""))).text#读取文本

在这之前需要调用功能

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

然而WebDriverWait有个缺陷,一些特定的按钮的路径加载出来了,但点击链接还未加载完,因此,在点击特定的按钮时可以结合

time.sleep()、find_element_by_xpath("").click()点击并读取文本,例如

time.sleep(0.5)     #加载等待
driver.find_element_by_xpath("").click() #点击窗口退出按钮
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,""))).click()
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,""))).text

以下为主要步骤:

创建网页窗口,这里采用的是google浏览器

opt = webdriver.ChromeOptions()   #创建浏览
#opt.set_headless()    #无窗口模式
#driver.maximize_window()   #最大化窗口
driver = webdriver.Chrome(options=opt)  #创建浏览器对象
​
print("正在打开网页")
driver.get('http://') #打开网页

一般的打开网页的审查元素,用小箭头点击目标区域查看对应代码块,右键Copy Xpath复制路径,这里无列表块可以直接使用Copy Xpath的路径访问

可以通过find_element_by_xpath根据相应xpath路径找到填写区域,使用send_keys进行填写

time.sleep(1)     #加载等待
print("正在填写账号")
# 填入账号
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/form/div[2]/div[3]/div[1]/div[2]/div/div/span/span/input")
# 清空原有内容
elem.clear()
# 填入账号
elem.send_keys("")

点击登录按钮,同样的Copy Xpath路径

time.sleep(1)     #加载等待
print("正在登录")
# 登录按钮并单击
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/form/div[5]/div/div/span/button").click()

部分网页客户端登陆后网页数据需要一定时间加载,可以设置久一点等待时间

网页中的列表类似于,其中红框是需要点击的区域

下方有页码块,页码块也可以直接通过Copy Xpath路径访问

对于访问列表元素的路径,给一个公式

//div[@class='']/.....

怎么完善代码,在Elements中找到列表图块和需要点击的元素位置并分别Copy Xpath

/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/div/div/div[2]/div[2]/div
/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/div/div/div[2]/div[2]/div/table/tbody/tr[1]/td/span/a[1]

这里注意列表图块需要选择带有px的代码行

这个列表名称为ant-table-body-inner,然后看元素与列表图块多出了一些路径

/table/tbody/tr[1]/td/span/a[1]

因此我们可以完善元素位置路径

//div[@class='ant-table-body-inner']/table/tbody/tr[1]/td/span/a[1]

列表中还需要依次访问其他元素,这里可以改成加循环的格式,其中i指的是第i个元素

//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]

点击元素完整命令行,使用click点击

WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]"))).click()#点击列表中的元素

点击后会弹出新的窗口,同样的,先定位新窗图块,在定位其中数据的位置,然后通过text直接读出文本,例如

result=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[3]"))).text

对于列表图块来说,其中的元素个数不会变动,但对于页码图块,其中元素的个数会发生改变,主要在开始几页和结尾几页

简单粗暴的方式就是设置几个if条件语句,下面采用的是填页码翻页的形式,当然也是为了避免中途网络延迟导致未加载报错,方便重新运行程序接着上次页码继续执行

kk=1 #从第几页开始
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")
elem.clear()
elem.send_keys(str(kk-1))
elem.send_keys(Keys.ENTER)
​
R=[]
​
for K in range(kk,503):#采用输入页码形式翻页
​
    time.sleep(0.5)
if K<5:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")
if K==5:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[12]/div[2]/input")
if K>5 and K<500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[13]/div[2]/input")
if K==500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[12]/div[2]/input")
if K>500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")
​
    elem.clear()
    elem.send_keys(str(K))
    elem.send_keys(Keys.ENTER)
    time.sleep(0.5)

上面是笨办法,其实可以直接定位向右图标位置并点击

driver.find_element_by_link_text("图标: right").click()#点击

如果是有"下一页"字符,就改成

driver.find_element_by_link_text("下一页").click()#点击

其他的细节代码,比如文本处理、条件,就根据自己想要的结果去完善

完整代码(已删掉账号密码网址)

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import csv
import datetime
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


opt = webdriver.ChromeOptions()   #创建浏览
opt.set_headless()    #无窗口模式
#driver.maximize_window()   #最大化窗口
driver = webdriver.Chrome(options=opt)  #创建浏览器对象

print("正在打开网页")
driver.get('') #打开网页

time.sleep(1)     #加载等待
print("正在填写账号")
# 查找账号填写位置
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/form/div[2]/div[3]/div[1]/div[2]/div/div/span/span/input")
# 清空原有内容
elem.clear()
# 填入账号
elem.send_keys("")

time.sleep(1)     #加载等待
print("正在填写密码")
# 查找密码填写位置
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/form/div[3]/div/div/span/span/input")
# 清空原有内容
elem.clear()
# 填入密码
elem.send_keys("")

time.sleep(1)     #加载等待
print("正在登录")
# 登录按钮并单击
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/form/div[5]/div/div/span/button").click()

print("等待加载页面")
time.sleep(5)     #加载等待

wenjian=datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S') #以开始时间作为数据导出的表格文件名
wenjian=wenjian+'.csv'

kk=1 #从第几页开始
elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")
elem.clear()
elem.send_keys(str(kk-1))
elem.send_keys(Keys.ENTER)

R=[]

for K in range(kk,503):#采用输入页码形式翻页

    time.sleep(0.5)
    if K<5:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")
    if K==5:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[12]/div[2]/input")
    if K>5 and K<500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[13]/div[2]/input")
    if K==500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[12]/div[2]/input")
    if K>500:
        elem = driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div/div/div/div/div/ul/li[11]/div[2]/input")

    elem.clear()
    elem.send_keys(str(K))
    elem.send_keys(Keys.ENTER)
    time.sleep(0.5)
    
    if K<502:
        
        for i in range(1,11):
            
            #if K==186 and i==9:#该位置的对象数据缺失,直接越过即可
            #    continue
            #if K==318 and i==8:#该位置的对象数据缺失,直接越过即可
            #    continue

            WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]"))).click()#点击列表中的元素
            time.sleep(0.5)     #加载等待
            result=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[3]"))).text
            result1=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[2]"))).text
            result2=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[2]/div/div[1]/div[2]"))).text
            result3=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[1]/div/div/div[2]"))).text

            while result3=='' or result2=='':  #如果第一次未读取到信息,则进行二次读取

                driver.find_element_by_xpath("//div[@class='ant-drawer-content-wrapper']/div/div/div[1]/button/i").click() #点击窗口退出按钮
                
                WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]"))).click()#点击列表中的元素
                time.sleep(1.5)     #加载等待
                result=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[3]"))).text
                result1=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[2]"))).text
                result2=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[2]/div/div[1]/div[2]"))).text
                result3=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[1]/div/div/div[2]"))).text
                
            result4=["第"+str(K)+"页序号"+str(i)+":",result,result1,result2,result3]  #打印结果
            
            R.append(result4)
            #print(result4)
            time.sleep(0.5)     #加载等待
            driver.find_element_by_xpath("//div[@class='ant-drawer-content-wrapper']/div/div/div[1]/button/i").click() #点击窗口退出按钮
            
            print('正在爬取'+str(K)+'页'+str(i)+'行')
            
        with open(wenjian,'w',encoding='utf-8',newline='') as fp:
            writer = csv.writer(fp)
            writer.writerows(R) #写入数据
            
    if K==502:
        
        for i in range(1,3):

            WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]"))).click()#点击列表中的元素
            time.sleep(0.5)     #加载等待
            result=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[3]"))).text
            result1=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[2]"))).text
            result2=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[2]/div/div[1]/div[2]"))).text
            result3=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[1]/div/div/div[2]"))).text

            while result3=='' or result2=='':  #如果第一次未读取信息,则进行二次读取

                driver.find_element_by_xpath("//div[@class='ant-drawer-content-wrapper']/div/div/div[1]/button/i").click() #点击窗口退出按钮
                
                WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body-inner']/table/tbody/tr["+str(i)+"]/td/span/a[1]"))).click()#点击列表中的元素
                time.sleep(1.5)     #加载等待
                result=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[3]"))).text
                result1=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-table-body']/table/tbody/tr["+str(i)+"]/td[2]"))).text
                result2=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[2]/div/div[1]/div[2]"))).text
                result3=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[@class='ant-drawer-content-wrapper']/div/div/div[2]/div/div[1]/div/div[2]/div/div[2]/div/div[1]/div/div/div[2]"))).text
                
            result4=["第"+str(K)+"页序号"+str(i)+":",result,result1,result2,result3]  #打印结果
            
            R.append(result4)
            #print(result4)
            time.sleep(0.5)     #加载等待
            driver.find_element_by_xpath("//div[@class='ant-drawer-content-wrapper']/div/div/div[1]/button/i").click() #点击窗口退出按钮

            print('正在爬取'+str(K)+'页'+str(i)+'行')

        with open(wenjian,'w',encoding='utf-8',newline='') as fp:
             writer = csv.writer(fp)
             writer.writerows(R) #写入数据

 

以上是关于Python+selenium 模拟网页点击爬虫车辆定位系统的主要内容,如果未能解决你的问题,请参考以下文章

如何用python模拟点击onclick

python selenium 自动化爬虫与测试网页利器

python selenium 自动化爬虫与测试网页利器

Python之Selenium自动化爬虫

爬虫-使用模拟浏览器操作(截取网页)

Python爬虫(二十三)_selenium案例:动态模拟页面点击