【问题标题】:How to loop through rows of the Excel sheet using openpyxl?如何使用openpyxl遍历Excel工作表的行?
【发布时间】:2020-03-12 13:08:29
【问题描述】:

我正在使用 Python、Selenium、openpyxl 来在线填写表格。 为了填写表格,我从 excel (.xlsx) 上的特定单元格中获取值。 (要测试代码,您可以只创建 2 列的 Excel 文件,在 A 列下插入一些名称,在 B 列下插入一些年龄。

  • 我从单元格A2 中获取此人的姓名并将其插入在线表格中
  • 我从单元格B2 获取此人的 LASTNAME 并将其插入在线表格中
  • 然后我点击“重置”(这是一个示例,但在实际代码中我将点击另存为草稿)。

我想创建一个循环,其中代码将从driver.get("https://www.roboform.com/filling-test-all-fields") 重新开始,再次转到我需要填写表格的页面,但这次我想采取:

  • 在单元格A3 中输入此人的姓名并将其插入在线表格中
  • 在单元格 B3 中,此人的 LASTNAME 并将其插入在线表格中
  • 然后再次点击“作为草稿发送”

然后,另一个循环从第 4 行插入数据,所以我想编程从driver.get("https://www.roboform.com/filling-test-all-fields") 再次读取我的代码,但这次从A4B4 中获取值,依此类推,直到excel上的行是空的。

使用以下代码,我可以将数据插入在线表单:

from selenium import webdriver
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.common.exceptions import NoSuchElementException
import openpyxl

driver: WebDriver = 
webdriver.Chrome("/Users/HHHHH/PycharmProjects/excel/driver/chromedriver")

driver.maximize_window()

excel_document = openpyxl.load_workbook(r"/Users/XPATH OF THE EXCEL FILE YOU CREATE TO TEST THIS CODE", 
data_only=True)

sheet = excel_document["Sheet1"]



driver.get("https://www.roboform.com/filling-test-all-fields")

#Insert in the form the Name of the person

prevsymbol = sheet["A2"].value
if prevsymbol == None:
    pass
else:
    try:
        driver.find_element_by_name("02frstname").send_keys(sheet["A2"].value)
    except NoSuchElementException:
        print("A2:(name) Not Found")

#Insert in the form the Last Name of the person

prevsymbol = sheet["B2"].value
if prevsymbol == None:
    pass
else:
    try:
        driver.find_element_by_name("04lastname").send_keys(sheet["B2"].value)
    except NoSuchElementException:
        print("B2:(Lastname) Not Found")

#click Save as a draft

driver.find_element_by_xpath("//*[@value='Reset']").click()

【问题讨论】:

    标签: python excel selenium loops rows


    【解决方案1】:

    您可以使用max_row 属性获取工作表中的行数。于是,代码变成了:

    from selenium import webdriver
    from selenium.webdriver.chrome.webdriver import WebDriver
    from selenium.common.exceptions import NoSuchElementException
    import openpyxl
    
    driver: WebDriver = 
    webdriver.Chrome("/Users/HHHHH/PycharmProjects/excel/driver/chromedriver")
    
    driver.maximize_window()
    
    excel_document = openpyxl.load_workbook(r"/Users/HHHHH/Desktop/testtesttest1.xlsx", 
    data_only=True)
    
    sheet = excel_document["Sheet1"]
    
    for i in range(1, sheet.max_row+1):
        driver.get("https://XXXXXXXXXX")    
        # Insert in the form the Name of the person
        cell = "A" + str(i)
        prevsymbol = sheet[cell].value
        # Note that instead of doing the work at the else clause, you can negate the term
        if prevsymbol is not None:
            try:
                # Note that we can use prevsymbol here, instead of referring to cell once again
                driver.find_element_by_id("name").send_keys(prevsymbol)
            except NoSuchElementException:
                #
                print(cell + ":(name) Not Found")
    
        # Insert in the form the Age of the person  
        cell = "B" + str(i)
        prevsymbol = sheet[cell].value
        if prevsymbol is not None:
            try:
                driver.find_element_by_id("age").send_keys(prevsymbol)
            except NoSuchElementException:
                print(cell + ":(Age) Not Found")
    
        # Click Save as a draft    
        driver.find_element_by_xpath("xpath_save_as_draft").click()
    

    【讨论】:

    • prevsymbol = sheet["A" + str(i)].value AttributeError: 'tuple' object has no attribute 'value' 为了方便起见,如果您创建一个包含两列和插入一个随机名称和另一个随机年龄,然后按照此代码(更改驱动程序的路径和代码找到您在计算机上创建的 excel 文件的路径)并添加这些详细信息:driver.get ("roboform.com/filling-test-all-fields") driver.find_element_by_name("02frstname").send_keys(prevsymbol) driver.find_element_by_name("04lastname").send_keys(prevsymbol)
    • @Alessio 我发现了问题所在。范围指定不正确(Python 范围从 0 开始,而 Excel 范围从 1 开始)。我正在更新我的解决方案。
    【解决方案2】:

    我创建了一个助手类,请查看它是否满足您的目的。此代码是在旧版本的 openpyxl 中完成的。如果需要,请更新代码。

    
    class OpenpyxlImport(object):
        def __init__(self, file):
            self.file = file
            if self.file.name.endswith('.xls'):
                self.wb = self.xls_to_xlsx(self.file)
            else:
                self.wb = load_workbook(self.file)
            self.sheets = self.wb.worksheets
    
        def to_camelcase(self, string):
            text = re.sub(r'(?!^)_([a-zA-Z])', lambda m: ' ' + m.group(1).upper(), str(string))
            return text.upper()
    
        def to_snake_case(self, string):
            text = re.sub(r'\s', '_', str(string))
            return text.lower()
    
        def xls_to_xlsx(self, content):
            xls_book = xlrd.open_workbook(file_contents=content.read())
            workbook = openpyxlWorkbook()
    
            for i in range(0, xls_book.nsheets):
                xls_sheet = xls_book.sheet_by_index(i)
                sheet = workbook.active if i == 0 else workbook.create_sheet()
                sheet.title = xls_sheet.name
    
                for row in range(0, xls_sheet.nrows):
                    for col in range(0, xls_sheet.ncols):
                        sheet.cell(row=row + 1, column=col + 1).value = xls_sheet.cell_value(row, col)
            return workbook
    
        def tally_header(self, row, fields):
            # Strip whitespace in cell value
            for cell in row:
                cell.value = cell.value.rstrip()
            return [cell.value for cell in row] == fields
    
        def row_to_dict(self, row):
            dct = {}
            for cell in row:
                dct[self.to_snake_case(self.get_first_sheet()[cell.column + '1'].value)] = cell.value
            return dct
    
        def get_sheets(self):
            return self.sheets
    
        def get_first_sheet(self):
            return self.sheets[0]
    
        def get_sheet_rows(self):
            return tuple(self.get_first_sheet().iter_rows())
    
    # Usage
    excel = OpenpyxlImport(file)
    rows = excel.get_sheet_rows()
    if excel.tally_header(rows[0], self.fields):
        for row in rows[1:]:
            params = excel.row_to_dict(row)
    

    【讨论】:

    • 感谢 Roshan,但我是初学者,无法让您的示例适应我的示例。为方便起见,如果您创建一个包含 2 列的 excel 文件并在一个随机名称和另一个随机年龄中插入,那么您遵循此代码(更改驱动程序的路径和代码找到 excel 文件的路径您已在计算机上创建)并添加这些详细信息: driver.get("roboform.com/filling-test-all-fields") driver.find_element_by_name("02frstname").send_keys(prevsymbol) driver.find_element_by_name("04lastname" ).send_keys(prevsymbol) driver.find_element_by_xpath("//*[@value='Reset']").click()
    • 我想做的是,一旦程序以正确的在线表格将A2和B2中的数据写入并单击“另存为草稿”,程序就可以重新读取相同的代码从 driver.get("XXXXXXXXXX") 开始再次读取代码,但不是从 excel 中填充 A2 和 B2 中的值,而是可以填充值 A3 和 B3,然后再次循环以将值 A4 插入在线表格的一个窗口中,然后B4 在另一个窗口中,依此类推,直到找到一个完全空的行。
    • 在这里,阅读后您可以通过检查行长度来获取最新行以转到最新行,row_to_dict 为您提供该行的值。使用 index + 1 到最后一行给出空行填充然后 for i, value in enumerate(args): cell = self.ws.cell(row=self.row_idx, column=i + 1) cell.value = value where args is ['<name>', '<last_name>']
    • 好的,但是一旦代码从第一行插入数据,我如何告诉程序传递到第二行并执行相同的过程?有没有办法使用“重复”函数告诉代码需要从哪一点重复代码并更改 A3 中的 A2 和 B3 中的 B2?我尝试过使用 itinerate 函数,但它同时插入 A 列的所有行和 B 列的所有行,而我希望程序编写 A2,然后单击下一个在线窗口并插入 B2,然后单击另存为草稿,然后从一个窗口中的 A3 和下一个窗口中的 B3 等添加到新表单数据...
    猜你喜欢
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2022-11-16
    • 1970-01-01
    相关资源
    最近更新 更多