基于selenum+python爬取(下载)网站数据的实现

写在前面

对于刚接触爬虫的萌新来说,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:\demo\Test_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:\webdrivers\chromedriver.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('123456\n') # 输入新字符串
#这里加个等待时间,因为网页打开是需要时间,如果不加后续可能会执行出错。
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()
    #切换到弹出的窗口(开始)
    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)
    #切换到弹出的窗口(结束)
    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:\Users\seawq\Downloads'
    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的初衷就是为了做自动化测试的)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值