优化我的python银行webscraper

时间:2017-01-02 08:10:40

标签: python selenium web-scraping beautifulsoup

我正在使用Python 3.4创建一个登录我的银行帐户的网络浏览器,点击每个帐户复制余额,然后将总数添加到谷歌工作表中。

我得到了它的工作,但正如你从代码中看到的那样,它是重复的,丑陋的,长篇大论。

我发现了一些问题:

  1. 我相信我应该使用一个函数来遍历不同的帐户页面以获得平衡,然后将值分配给不同的变量。但是我想不出办法完成这件事。

  2. 将字符串转换为浮点似乎很乱,我想要做的是创建一个字符串即。通过剥离'$'和','进入浮动$ 1,000.00,是否有更优雅的方式?

    from selenium import webdriver 
    import time
    import bs4
    import gspread
    from oauth2client.service_account import serviceAccountCredentials
    
    driver = webdriver.Chrome()
    driver.get(bank url) 
    
    
    inputElement = driver.find_element_by_id("dUsername")
    inputElement.send_keys('username')
    pwdElement = driver.find_element_by_id("password")
    pwdElement.send_keys('password')
    driver.find_element_by_id('loginBtn').click()
    time.sleep(3)
    
    #copies saving account balance
    driver.find_element_by_link_text('Savings').click()
    time.sleep(3)
    html = driver.page_source
    soup = bs4.BeautifulSoup(html)
    elems=soup.select('#CurrentBalanceAmount')
    SavingsAcc = float(elems[0].getText().strip('$').replace(',',''))
    driver.back()
    
    #copy cheque balance
    driver.find_element_by_link_text('cheque').click()
    time.sleep(3)
    html = driver.page_source
    soup = bs4.BeautifulSoup(html)
    elems=soup.select('#CurrentBalanceAmount')
    ChequeAcc = float(elems[0].getText().strip('$').replace(',',''))
    Total = SavingsAcc+ ChequeACC  
    driver.back()
    

2 个答案:

答案 0 :(得分:0)

尝试以下代码:

from selenium import webdriver 
import time
import bs4
import gspread
from oauth2client.service_account import serviceAccountCredentials

driver = webdriver.Chrome()
driver.get(bank url) 


inputElement = driver.find_element_by_id("dUsername")
inputElement.send_keys('username')
pwdElement = driver.find_element_by_id("password")
pwdElement.send_keys('password')
driver.find_element_by_id('loginBtn').click()
time.sleep(3)

def getBalance(accountType):
    driver.find_element_by_link_text(accountType).click()
    time.sleep(3)
    html = driver.page_source
    soup = bs4.BeautifulSoup(html)
    elems=soup.select('#CurrentBalanceAmount')
    return float(elems[0].getText().strip('$').replace(',',''))

#copies saving account balance
SavingsAcc = getBalance('Savings')
driver.back()
#copy cheque balance
ChequeACC = getBalance('cheque')    

Total = SavingsAcc+ ChequeACC  
driver.back()

制作方法getBalance,您必须在其中传递帐户类型,该类型会返回余额金额。

注意:您可以根据自己的方便driver.back拨打getBalance电话,但在return声明之前。

与将string转换为float相关,除了现有逻辑之外,我还不知道任何其他更好的方法。由于它现在已经转变为一种方法,我希望现在它不会给你带来太多麻烦。有float方法,它将字符串转换为浮点数,但不接受$,。更多详情here

注意:如果#CurrentBalanceAmount值每次更改为不同的帐户类型,您可以参数化accountType

答案 1 :(得分:0)

我会使用几个python习语来清理代码:

  • 将所有代码包装在函数中
    • 一般来说,将代码放入函数可以更容易阅读和遵循
    • 运行python脚本(python foo.py)时,python解释器按顺序依次运行每一行。当遇到函数定义时,它只运行定义行(def bar():),而不是函数中的代码。
    • 这篇文章似乎是获取更多信息的好地方:Understanding Python's Execution Model
  • 使用if __name__ == "__main__":惯用法使其成为可导入的模块
    • 与上面的项目符号类似,这使您可以更好地控制代码的执行方式和时间,可移植性以及可重用性。
    • “可导入模块”表示您可以将代码编写在一个文件中,然后将该代码导入另一个模块。
    • 有关if __name__ == "__main__"的更多信息:What does if name == “main”: do?
  • 使用try / finally确保清理驱动程序实例
  • 使用显式等待与页面交互,因此您无需使用sleep
    • 默认情况下,Selenium会尝试立即查找并返回内容。如果该元素尚未加载,则Selenium会抛出异常,因为它不够智能,无法等待它加载。
    • 显式等待内置于Selenium中,允许您的代码等待元素加载到页面中。默认情况下,它每隔半秒检查一次,看是否加载了元素。如果没有,则只需再过半秒再试一次。如果有,则返回元素。如果它没有加载,Wait对象将抛出TimeoutException。
    • 更多信息:Explicit and Implicit Waits
    • 在这里:WAIT IN SELENIUM PYTHON

代码(由于显而易见的原因未经测试):

from selenium import webdriver
from explicit import waiter, ID  # This package makes explicit waits easier to use
                                 # pip install explicit
from selenium.webdriver.common.by import By

# Are any of these needed?
# import time
# import bs4
# import gspread
# from oauth2client.service_account import serviceAccountCredentials


def bank_login(driver, username, password):
    """Log into the bank account"""
    waiter.find_write(driver, 'dUsername', username, by=ID)
    waiter.find_write(driver, 'password', password, by=ID, send_enter=True)


def get_amount(driver, source):
    """Click the page and scrape the amount"""
    # Click the page in question
    waiter.find_element(driver, source, by=By.LINK_TEXT).click()

    # Why are you using beautiful soup? Because it is faster?
    # time.sleep(3)
    # html = driver.page_source
    # soup = bs4.BeautifulSoup(html)
    # elems=soup.select('#CurrentBalanceAmount')
    # SavingsAcc = float(elems[0].getText().strip('$').replace(',',''))
    # driver.back()

    # I would do it this way:
    # When using explicit waits there is no need to explicitly sleep
    amount_str = waiter.find_element(driver, "CurrentBalanceAmount", by=ID).text
    # This conversion scheme will handle none $ characters too
    amount = float("".join([char for char in amount_str if char in ["1234567890."]]))

    driver.back()

    return amount


def main():
    driver = webdriver.Chrome()
    try:
        driver.get(bank_url)
        bank_login(driver, 'username', 'password')
        print(sum([get_amount(driver, source) for source in ['Savings', 'cheque']]))

    finally:
        driver.quit()  # Use this try/finally idiom to prevent a bunch of dead browsers instances


if __name__ == "__main__":
    main()

完全披露:我维护explicit包。如果您愿意,可以用相对较短的等待电话替换上面的waiter电话。如果您正在使用Selenium,那么值得花时间去理解并使用明确的等待。