对于刚接触爬虫的萌新来说,selenium方式是最友好的,虽然效率不高,但是比人工快,还保护眼睛,因为一开始没有用爬虫的时候,是一个个去人工 *** 作的。
任务来源:其实是我想从一个业务网站下载坐标到本地,建库,方便项目管理,数据质检。
Round 1
一开始没想用selenium,因为效率低。然后下载了相关的软件,把页面分析了断断续续一个月也没找到突破口,因为坐标可能是敏感数据,所以进行了加密。但是导出的时候是可以。
Round 2
后来还特意买了爬虫的书籍来看,有点小题大作,加上书籍内容广泛但不是丰富,其实网上是资源更多,更便捷。研究半天还是决定先用selenium试下,因为着急用数据库成果。
准备工作:安装好谷歌浏览器chorme和对应版本的浏览器驱动chromedriver。
首先要导入需要用到的库
from selenium import webdriver from selenium.webdriver.common.by import By import time #非常关键,因为selenium *** 作网页会有加载的时间,必须要有等待,等加载完毕后再 *** 作。 import pandas as pd #读取xls用到 import os #重命名文件用到
实现路径是:
1.需要把项目清单xls文件导入python,添加做成列表,以便在后面根据调用这个列表进行逐一爬取。(这里我是直接在网上搜索到然后复制修改成自己想要的,还没有完全理解透)
#定义全局变量 result = [] #读入xls文件项目名称的函数 def excel_one_line_to_list(): df = pd.read_excel("D:demoTest_20211116224417原始.xls", usecols=[1],names=None) # 读取项目名称列,不要列名 df_li = df.values.tolist() for s_li in df_li: result.append(s_li[0]) if __name__ == '__main__': excel_one_line_to_list()
2.调用浏览器驱动打开网页,通过预置的登录账号和密码登录网站()
# 创建 WebDriver 对象,指明使用chrome浏览器驱动 wd = webdriver.Chrome(r'd:webdriverschromedriver.exe') # 设置最大等待时长为 3秒 wd.implicitly_wait(3) # 调用WebDriver 对象的get方法 可以让浏览器打开指定网址,怕有杠精,此处省略了真正的网址 wd.get('http://XXXX/TdIndex.html') elements = wd.find_elements_by_xpath("//*[@id='txtLogin']") element = wd.find_element_by_id("txtLogin") element.clear() # 清除输入框已有的字符串 element.send_keys('qnz') # 输入新字符串 element = wd.find_element_by_id("txtPass") element.clear() # 清除输入框已有的字符串 element.send_keys('123456n') # 输入新字符串 #这里加个等待时间,因为网页打开是需要时间,如果不加后续可能会执行出错。 time.sleep(2)
3.登录完成后,跳转到第二个网页,因为登录成功后,页面会刷新到另一个页面,网址是不一样的,此时若不执行跳转,就无法进行下一步 *** 作,因为程序会一直在原来的网址 *** 作,它并不知道已经刷新了新的网址。(知识点:窗口切换)
# 获得打开的第一个窗口句柄 window_1 = wd.current_window_handle # 获得打开的所有的窗口句柄 windows = wd.window_handles # 切换到最新的窗口 for current_window in windows: if current_window != window_1: wd.switch_to.window(current_window) #print(wd.current_url)#打印当前 *** 作的网址#此处我注释调,调试的时候保留,以便验证确定是否已经跳转页面成功。
4.核心代码部分。这部分牵涉到的第一个知识点就是切换框架,因为要 *** 作的元素有在第一级框架,有在第二级框架的,所以需要进入框架、切出框架、回到主页等 *** 作。
第二个知识点就是异常处理。try/except的使用。因为是批量爬取,就会出现有些缺失的情况出现,所以不是所有的 *** 作都能成功,这时候用try/except来处理非常合适。 *** 作结束要关闭窗口,回到第一个窗口,如此循环。
#从网站下载文件的函数--↓--(开始) def download(XM_name): #print(wd.current_url) # 打印当前 *** 作的网址 #切换进入框架 wd.switch_to.frame('frmleft') #点击项目查询箱 wd.find_element(By.ID, 'menu_tree_5_span').click() wd.switch_to.frame('page_84953F0A-2845-1B2F-B6A6-8ED4854DD400') wd.switch_to.frame('yb') #清除上次输入的项目名称 wd.find_element(By.NAME, 'ywname').clear() #输入新的项目名称 wd.find_element(By.NAME, 'ywname').send_keys(XM_name) #点击查询 wd.find_element(By.CLASS_NAME,'icon_find').click() #等待缓冲 time.sleep(2) #点击项目查看 wd.find_element_by_xpath("//div/a[last()-1]").click() #切换到d出的窗口(开始) time.sleep(1) # 获得打开的第一个窗口句柄 window_1 = wd.current_window_handle # 获得打开的所有的窗口句柄 windows = wd.window_handles # 切换到最新的窗口 for current_window in windows: if current_window != window_1: wd.switch_to.window(current_window) #切换到d出的窗口(结束) try: jie_duan='验收' # 点击验收坐标导入 wd.find_element_by_xpath('//*[@id="rc_tree"]/li/ul/li[3]/ul/li[3]/div/span[5]').click() time.sleep(1) # 切换进入框架#切入第二frame(计数从0开始,因为frame的Id和name一致在变化,不能用它们来定位) wd.switch_to.frame(1) # 点击下载(项目区范围线) wd.find_element_by_xpath('//*[@id="maingrid|2|r1001|c104"]/div/div/a').click() # 切换进入内部frame wd.switch_to.frame('_Dialogframe_0') # 勾选shp wd.find_element_by_xpath('//*[@value=".txt"]').click() # 返回上一级frame wd.switch_to.parent_frame() # 点击确定 wd.find_element_by_xpath('//*[@id="_ButtonOK_0"]').click() time.sleep(2) # 等待保存动作完结,防止超前 *** 作,没有这个等待会直接改变上一个文件。 get(XM_name,jie_duan) print(XM_name, '---验收坐标下载成功---') except: print(XM_name,'---无验收坐标,验收坐标下载失败!---') try: jie_duan = '计划' wd.switch_to.default_content() # 点击计划坐标导入 wd.find_element_by_xpath('//*[@id="rc_tree"]/li/ul/li[1]/ul/li[3]/div/span[5]').click() time.sleep(1) # 切换进入框架#切入第二frame(计数从0开始,因为frame的Id和name一致在变化,不能用它们来定位) wd.switch_to.frame(2) # 点击下载(项目区范围线) wd.find_element_by_xpath('//*[@id="maingrid|2|r1001|c104"]/div/div/a').click() # 切换进入内部frame wd.switch_to.frame('_Dialogframe_0') # 勾选shp wd.find_element_by_xpath('//*[@value=".txt"]').click() # 返回上一级frame wd.switch_to.parent_frame() # 点击确定 wd.find_element_by_xpath('//*[@id="_ButtonOK_0"]').click() time.sleep(2) # 等待保存动作完结,防止超前 *** 作,没有这个等待会直接改变上一个文件。 get(XM_name,jie_duan) print(XM_name,'---计划坐标下载成功---') except: print(XM_name, '---无坐标,下载失败---') wd.close()#关闭窗口 wd.switch_to.window(windows[0])#切换到第一个窗口 #print(wd.current_url) # 打印当前 *** 作的网址 return #从网站下载文件的函数--↑--(结束)
5.上一步调用了一个保存文件的时候对文件进行重命名的函数,因为下载的文件默认已经有名称了,而且下载时并没有重命名的机会,所以需要对下载保存目录下的最新文件进行重命名即可,名称就是从导入的项目名称传递进去即可。(这段代码也是从网上找的,修改了一下就用了)
#对下载的文件进行重命名的函数 def get(filename,j_d): path = r'C:UsersseawqDownloads' list1 = os.listdir(path) list2 = [x for x in list1 if '.txt' in x] #获取文件夹内的后缀为txt的文件列表 list2.sort(key=lambda x:os.path.getmtime(path+'\'+x)) #文件列表按!修改!时间排序 time.sleep(1) old = os.path.join(path,list2[-1]) new = os.path.join(path,filename+'_'+j_d+'.txt') os.rename(old,new) return new#可以不用返回值,因为后面没有调用了
6.最后就是循环调用的部分了。最后关闭窗口,搞定!
#调用上面的函数,循环遍历整个列表 i=1 for Nresult in result: download(Nresult) i+=1 print(str(i)+'/1709') print('-------运行完毕-------') wd.quit()小结
其实这次用selenium来实现,花时间最多的就是frame(框架)的切换,研究了很久。关于selenium选择元素的方法,学习了css和Xpath,但是现在流行的是Xpath,也相对简单,主流浏览器的检查要素页面都自带提供右键复制Xpath路径和Xpath绝对路径的功能,非常好用,不用你去琢磨应该用ID还是什么来选择,直接复制粘贴到程序里就能用(当然一定要考虑是否有frame,复制的Xpath路径是不考虑frame的,因为我被坑过)。总之对于想学爬虫的初学者来说selenium是非常好的选择,虽然高手都说用selenium来实现不算爬虫,只能说是自动化(seleninum的初衷就是为了做自动化测试的)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)