vlambda博客
学习文章列表

利用webdriver, openpyxl标记邮件中的英语并导出到Excel表格中

零 为什么要写这段代码?

由于工作原因需要与英语国家的同事经常视频和邮件沟通,英语虽然是我的专业,但是已经很多年没有直接跟母语国家的人直接交流了,所以无论口语和书面语都有很多退化,也不地道。所以知道不足,就要学习的地道表达方式。邮件就是一个很好的学习途径,我需要标记出句子,然后导入到一个Excel表格。

一 . 标记句子

我的邮件是outlook的服务器,所以用outlook直接登录。outlook有个微软代办的功能,可以在邮件中选定任意一一段话作为代办事宜。如下图,选中后然后点击勾后,就会储存在代办事宜中。


二. 使用webdriver读取每个Task的内容

我们通过分析页面上的元素,可以得到Tasks位置上的元素和它的text就是图中197的任务总个数。

 listcount = self.browser.find_element_by_xpath('/html/body/div/div/div[3]/div[1]/div/div[2]/nav/ul/div[5]/li/div/div/span[3]')
 totaltask = int(listcount.text)

然后再分析任务中每个任务的x-path发现他们的规律是:

'/html/body/div/div/div[3]/span[1]/div/div[2]/div/div/div[1]/div/div/div/div[%d]/div/div[1]/div/button'中%d的位置从1到最后一个197分别表示最新的任务到最旧的任务, 所以这里可以使用迭代完成定位并导出任务的内容。

三. 每个任务需要用webdriver模拟鼠标点击

因为网页的显示有限,任务达到一定数量后就会自动隐藏,需要通过鼠标点击后面的任务才会显示出来。

四. 把任务内容写入文件

通过迭代导出每个任务内容后写入一个列表中并储存在一个二进制文件WE.txt中。

五. 对比数量再更新

当有新的任务加入后,我们需要对比新的任务和WE.txt中的任务个数,如果有更新的数量,就直接读取更新部分,再写入WE.txt中。注意:本例不能删除网页中已经储存的任务,如果确实需要删除,可以把WE.txt文件删除再重新把所有任务读取一遍。

六. 使用openpyxl把数据写入Excel表格中,方便查看

openpyxl以前也用过,这次也只是简单的把WE.txt中的列表数据写入Excel表格中,其中主要用到了Alignment, Font两个类

七. 使用app,py把两部分webdriver和openpyxl两部分合并

最后得到的Excel表格

八. 源代码:

 #encoding = UTF-8
 #we.py 使用webdriver读取网页上的任务,并写入WE.txt
 
 from selenium import webdriver
 from selenium.webdriver.common.action_chains import ActionChains
 from selenium.webdriver.support.wait import WebDriverWait
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.common.by import By
 from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
 import time
 import os
 import sys
 import pickle
 
 
 
 class datawe():
     def __init__(self):
         #为了避免browser.get()的长时间加载
         desired_capabilities = DesiredCapabilities.CHROME
         desired_capabilities["pageLoadStrategy"] = "none"
         self.browser = webdriver.Chrome()
     #定义显性等待,参数为需要等待出现的具体元素的xpath值
     def waitok(self, location):
         locator = (By.XPATH, location)
         try:#由于需要上传大量文件,需要长时间等待,所有最大为10分钟
             WebDriverWait(self.browser, 600, 0.5).until(EC.presence_of_element_located(locator))
             #print('Get the target.%s' % location)
         except TimeoutException:
             print('网络超时,页面加载失败。')
             browser.quit()#如果出现长时间(600秒)不能加载完成,就关闭浏览器,退出程序。
             sys.exit()
             
         
     def getlist(self):        
         
         self.browser.get('https://outlook.office365.com/')
         #browser.maximize_window()#最大化浏览器窗口
         self.waitok('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div/div/div[2]/div[2]/div/input[1]')
         mailaddress = self.browser.find_element_by_xpath('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div/div/div[2]/div[2]/div/input[1]')
         mailaddress.send_keys('myemailaddress')
         self.waitok('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div/div/div[4]/div/div/div/div/input')
         nextstep = self.browser.find_element_by_xpath('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div/div/div[4]/div/div/div/div/input')
         time.sleep(1)
         nextstep.click()
         self.waitok('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div[2]/div/div[2]/input')
         password = self.browser.find_element_by_xpath('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div[2]/div/div[2]/input')
         #password.send_keys(input('Input Email password:'))
         password.send_keys('mypassword')
         login = self.browser.find_element_by_xpath('/html/body/div/form[1]/div/div/div[2]/div[2]/div[2]/div/div[2]/div/div[3]/div[2]/div/div/div/div/input')
         time.sleep(1)
         login.click()
         self.waitok('/html/body/div/form/div[1]/div/div[2]/div[2]/div/div[2]/div/div[3]/div[1]/div/label/span')
         nodisplay = self.browser.find_element_by_xpath('/html/body/div/form/div[1]/div/div[2]/div[2]/div/div[2]/div/div[3]/div[1]/div/label/span')
         nodisplay.click()
         confirmyes = self.browser.find_element_by_xpath('/html/body/div/form/div[1]/div/div[2]/div[2]/div/div[2]/div/div[3]/div[2]/div/div/div[2]/input')
         time.sleep(1)
         confirmyes.click()
         self.waitok('/html/body/div[2]/div/div[2]/div[1]/div/div[1]/div[2]/div/div[2]/div[4]/div/a/span/i')
         todo = self.browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div/div[1]/div[2]/div/div[2]/div[4]/div/a/span/i')
         todo.click()
         self.waitok('/html/body/div/div/div[3]/div[1]/div/div[2]/nav/ul/div[5]/li/div/div/span[3]')
         #找到任务的个数,及记录句子的总个数
         listcount = self.browser.find_element_by_xpath('/html/body/div/div/div[3]/div[1]/div/div[2]/nav/ul/div[5]/li/div/div/span[3]')
         totaltask = int(listcount.text)
         print('总句子个数为:%d' % totaltask)
         
         #读取储存在WE.txt文件中的数据,如果第一运行程序,就新建一个列表,并设置储存的任务数为0
         try:
             with open(r'C:\Users\sonic\Desktop\WE\WE.txt', 'rb') as f1:
                 sumwe = pickle.load(f1)
                 savedtask = len(sumwe)
                 print('储存的句子个数为:%d' % savedtask)        
         except:
             sumwe = []
             savedtask = 0
             print('储存的句子个数为:%d' % savedtask)
             
         #需要更新的数量
         updatetask = totaltask - savedtask
         print('增加的句子个数为:%d' % updatetask)
         #需要读取的次数为需要更新的数量
         for i in range(1, updatetask+1):
             elements = self.browser.find_element_by_xpath('/html/body/div/div/div[3]/span[1]/div/div[2]/div/div/div[1]/div/div/div/div[%d]/div/div[1]/div/button' % i)
             #由于网页上面自动隐藏一部分任务,所以我们需要点击一下,让隐藏的部分显示出来
             elements.click()
             string = elements.text
             #读取到任务内容后,切片取出我们需要的部分,然后append进列表中,注意这里最新的一个任务最先读取,但添加在更新列表后的第一个位置
             english = string[:-3]
             print('%s : %s' % (i, english))
             sumwe.append(english)
 
 
         self.browser.quit()
                         
             
         with open(r'WE.txt', 'wb') as f2:
             pickle.dump(sumwe,f2)
         return sumwe
 
 if __name__ == '__main__':
     we = datawe()
     englishlist = we.getlist()
 


 #excel.py 使用openpyxl把WE.txt的数据写入English.xlsx
 
 import openpyxl
 import pickle
 from openpyxl.styles import Alignment,Font
 
 def write_excel():
     #读取储存的Excel文件数据,如果第一次运行程序,就新建一个表格
     try:
         wb = openpyxl.load_workbook('English.xlsx')
     except FileNotFoundError:
         wb = openpyxl.Workbook()
         
     sh = wb.active
     #设置第一行标题的格式
     sh['A1'] = 'NO.'
     sh['A1'].alignment = Alignment(horizontal='left', wrapText=True, vertical='center' )
     sh['A1'].font = Font(b=True, name='微软雅黑')
     sh['B1'] = 'Words and Expressions'
     sh['B1'].alignment = Alignment(horizontal='left', wrapText=True, vertical='center' )
     sh['B1'].font = Font(b=True, name='微软雅黑')
     sh['C1'] = 'Explain'
     sh['C1'].alignment = Alignment(horizontal='left', wrapText=True, vertical='center' )
     sh['C1'].font = Font(b=True, name='微软雅黑')
 
     #设置行,列的宽,高
     sh.column_dimensions['B'].width = 100
     sh.row_dimensions[1].height = 20
 
     #读取网站的储存数据
     with open('WE.txt', 'rb') as f1:
         english = pickle.load(f1)
     #比较网站的储存数据与Excel储存数据,得到需要更新的数据个数
     n = len(english)
     saved_n = sh.max_row - 1
     update_n = n - saved_n
 
     #需要更新的个数大于0才开始更新
     #由于更新的任务数据写在WE.txt列表数据的最后,所以我们需要从倒数的位置的开始读取
     if update_n > 0:
         for each in english[-update_n:]:
             
             Acell = ''.join(['A', str(n+1)])
             sh[Acell] = n
             sh[Acell].alignment = Alignment(horizontal='left', wrapText=True, vertical='center' )
             sh[Acell].font = Font(name='微软雅黑')
             Bcell = ''.join(['B', str(n+1)])
             sh[Bcell] = each
             sh[Bcell].alignment = Alignment(horizontal='left', wrapText=True, vertical='center' )
             sh[Bcell].font = Font(name='微软雅黑')
             n -= 1
             #print('增加第%s行:%s.' % (Acell, each))
 
     else:
         print('没有更新。')
 
     wb.save('English.xlsx')
 
 if __name__ == '__main__':
     write_excel()
 
 #app.py 合并前面两段程序
 import we
 import excel
 
 we = we.datawe()
 we.getlist()
 excel.write_excel()