РЕДАКТИРОВАТЬ: см. Ниже для обновления.Ниже приведен пример «завершенного» кода, который работает успешно, но использует не лучшие практики.
У меня есть большая форма через портал поставщиков, над которой я работаю над автоматизацией заполнения данными из Excel (вытягивая изхранилище данных, эта часть была легкой).Я пытаюсь поместить данные в поля (001) (Item), (001) (GTIN), (002) (Item) и т. Д. Для всех полей.

В частности, это код веб-сайта, с которым я работаю:
<tr id="0lineDetailheader" data-bind="attr: {'id': $index() + 'lineDetailheader'}">
<!-- ko if: $parent.showExpColAll --><!-- /ko -->
<td>
<input type="checkbox" data-bind="checked: chkSelected">
<div style="margin-top: -20px; margin-left: -21px; position: absolute;" data-bind="style: { marginLeft: $parent.showExpColAll() ? '-45px' : '-21px', position: 'absolute', marginTop: '-20px' }, visible: hasError()">
<i title="Line has at least 1 error." class="fa fa-asterisk" style="color: rgb(204, 0, 0); cursor: pointer;">
</i>
</div>
</td>
<td>
<span data-bind="text: lineNumber($index())">001</span>
</td>
<td>
<input title="Item" class="form-control" onkeypress="return ValidateNum();" type="text" maxlength="9" data-bind="value: ItemNumber, readOnly: lineProtected">
</td>
<td>
<input title="GTIN" class="form-control" onkeypress="return ValidateNum();" type="text" maxlength="14" data-bind="value: GTIN, readOnly: lineProtected">
<span class="pull-right" data-bind="text: GTINlabel"></span>
</td>
<td>
<input title="Supplier Stock #: null" class="form-control" id="VndrStk" onkeypress="return validateAlphaNumPlus()" type="text" maxlength="45" data-bind="attr: { title: 'Supplier Stock #: ' + SupplierStockNumber()}, value: SupplierStockNumber, readOnly: lineProtected">
</td>
<td>
<input name="InvoiceQuantity" title="Invoice Quantity" class="form-control" onkeypress="return validateFloatKeyPress(this, event)" type="text" maxlength="9" data-bind="value: QtyInvoiced">
</td>
<td>
<input title="Selling Unit" class="form-control" onkeypress="return ValidateNum();" type="text" maxlength="9" data-bind="value: SellingUnits, readOnly: lineProtected">
</td>
<td>
<input title="Item Cost" class="form-control" onkeypress="return validateFloatKeyPress(this, event)" type="text" maxlength="9" data-bind="value: UnitPrice, readOnly: costProtected">
</td>
<td class="text-right">
<span title="Extended Cost" data-bind="text: ExtendedCost">0.00</span>
</td>
<td class="text-right">
<span title="Line Amount" data-bind="text: LineAmount">0.00</span>
</td>
</tr>
Я специально пытаюсь найти поле элемента в 0lineDetailheader и т. Д.
<input title="Item" class="form-control" onkeypress="return ValidateNum();" type="text" maxlength="9" data-bind="value: ItemNumber, readOnly: lineProtected">
С некоторыми другими полями / кнопками в рабочем процессе я получил приведенные ниже фрагменты для успешной работы, но не здесь.
Set ElementCol = IE.document.getElementsByClassName("lineDetailsHeader")
ElementCol.Item(0).Select
With IE.document
.all("InvoiceNbr").Value = ws.Range("C3").Value
.all("invoiceDate").Value = ws.Range("C4").Value
.all("shipDate").Value = ws.Range("C5").Value
End With
Я также пытался использовать sendkeys, что крайне неэффективно, но ядаже не смог добраться до поля: /
Я подозреваю, что решение будет очевидно для некоторых более сведущих в HTML или Java, но, увы, это не я.
РЕДАКТИРОВАТЬ: ОБНОВЛЕНИЕ 105.54 6/26/18
Благодаря ответу ниже я попал в поле.Все еще не знаете, как перебирать строки 001, 002 и т. Д. Через индексПолный код, который я использую ниже.Я использую sendkey в некоторых областях, потому что веб-форма имеет эти красные звездочки рядом с ней, если она не регистрирует завершение, и я не знаю, как вызвать это с "реальным" кодом.
Public Sub WebFiller()
'Some definitions
Dim i As Long
Dim HWNDSrc As Long
'Set up workbook
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Invoice")
'Open Retail Link
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.navigate REDACTED
'Let website load
While IE.ReadyState <> 4
DoEvents
Wend
'Input store value
With IE.document
.all("inputStore").Value = ws.Range("C1").Value
.all("inputStore").Focus
.all("inputStore").Select
End With
'The section only updates once it recognizes that values have been input. This seems to get force that interaction. It is definitely not best prcatice though.
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:02"))
'Finish the button clicks on the first page, giving it appropriate refresh time.
Set ElementCol = IE.document.getElementsByClassName("btn btn-primary")
ElementCol.Item(0).Click
Application.Wait (Now + TimeValue("0:00:02"))
Set ElementCol = IE.document.getElementsByClassName("btn btn-primary pull-right")
ElementCol.Item(0).Click
Application.Wait (Now + TimeValue("0:00:02"))
'Let website load
While IE.ReadyState <> 4
DoEvents
Wend
'Fill in the info at the top of the page
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
With IE.document
.all("InvoiceNbr").Value = ws.Range("C3").Value
.all("invoiceDate").Value = ws.Range("C4").Value
.all("shipDate").Value = ws.Range("C5").Value
.all("InvoiceNbr").Select
End With
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:02"))
'Add the necessary number of rows
For i = 1 To ws.Range("C7").Value - 1
Set ElementCol = IE.document.getElementsByClassName("fa fa-plus fa-lg")
ElementCol.Item(0).Click
Next i
'start first line "Index 0"
With IE.document
.querySelector("input[title='Item']").Value = ws.Range("B12").Value
.querySelector("input[title='GTIN']").Value = ws.Range("C12").Value
.querySelector("input[title='Invoice Quantity']").Value = ws.Range("E12").Value
.querySelector("input[title='Item Cost']").Value = ws.Range("G12").Value
.querySelector("input[title='Item Cost']").FireEvent "onkeypress"
End With
'start second line "Index 1"
With IE.document
.querySelector("input[title='Item']").Value = ws.Range("B15").Value
'etc etc but this doens't work
End With
End Sub
EDIT7.16.18 (последнее обновление): Вот полный код работы.Он подключается через куб OLAP к некоторым сводным таблицам, поэтому, если вы пытаетесь скопировать это, вам, вероятно, придется изменить способ взаимодействия со слайсерами.
В сводной таблице есть следующий код:
Private Sub Worksheet_PivotTableUpdate _
(ByVal Target As PivotTable)
' first remove filter
Sheets("Invoice").Range("$E$11:$E$43").AutoFilter Field:=1
' then apply it again
Sheets("Invoice").Range("$E$11:$E$43").AutoFilter Field:=1, Criteria1:="<>0"
End Sub
Создает визуальный фильтр на предварительно отформатированной странице, чтобы эмулировать создание "счета-фактуры", если необходимо было ввести вручную.Это отличный способ применить специальные фильтры к спискам, если вы используете функции типа column / row, index / match / match, vlookup / hlookup.
На основной вкладке счета есть этот код.На портале поставщика есть список отправленных документов, поэтому я вставил этот контрольный список / проверочные листы, чтобы создать рабочий процесс.Имея список счетов для «просмотра», макрос просматривает их, проверяет, был ли он отправлен, что счет-фактура соответствует ожидаемому и что это не кредитный счет, который необходимо обрабатывать отдельно.В среднем это составляет около 75 секунд / счет, по сравнению с примерно 8 минутами для сотрудника, который делал это.Я очень доволен этим, даже если (как упомянуто выше) я продолжал использовать sendkeys, что определенно не является лучшей практикой.
Код помечен довольно хорошо, но дайте мне знать, если какая-либо из моих логикинеясно.
Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal HWND As LongPtr) As LongPtr
Public Sub InvoiceFiller()
'Purpose: To expedite WebEDI experience. Manual input takes too long.
'Some definitions
Dim i, r As Long
Dim lRow1, lRow2 As Long
Dim c As Range
Dim HWNDSrc As Long 'had to use sendkeys, couldn't figure out how else to trigger certain parts
Dim ws As Worksheet 'this is the invoice worksheet
Dim cs As Worksheet 'this is the checklist worksheet
Dim vs As Worksheet 'this is the validation against retail link's database
Dim cm As Worksheet 'this is the main cube report. All slicers affect both cubes
Dim wb As Workbook
Dim IE As Object
Dim SliceArr As Variant
Dim SliceVal As Variant
'Set up workbook shortcuts
Set wb = ThisWorkbook
Set ws = wb.Sheets("Invoice")
Set cs = wb.Sheets("Checklist")
Set vs = wb.Sheets("Validation")
Set cm = wb.Sheets("CUBE_MAIN")
''''''''''''''''''''''''''''''''''''''
'Start of Checklist component
'This sets up the ability to loop a range of invoices, referencing against the validation tab
'Copy tickets to the checklist page
lRow1 = cm.Cells(Rows.Count, 2).End(xlUp).Row - 1
lRow2 = cs.Cells(Rows.Count, 1).End(xlUp).Row
'First copy the tickets
cm.Range(cm.Cells(8, 1), cm.Cells(lRow1, 1)).Copy
cs.Range(cs.Cells(lRow2 + 1, 1), cs.Cells(lRow2 + 1 + lRow1 - 8, 1)).PasteSpecial xlPasteValues
'Next copy the dates
cm.Range(cm.Cells(8, 4), cm.Cells(lRow1, 4)).Copy
cs.Range(cs.Cells(lRow2 + 1, 2), cs.Cells(lRow2 + 1 + lRow1 - 8, 2)).PasteSpecial xlPasteValues
'Then copy the stores
cm.Range(cm.Cells(8, 3), cm.Cells(lRow1, 3)).Copy
cs.Range(cs.Cells(lRow2 + 1, 3), cs.Cells(lRow2 + 1 + lRow1 - 8, 3)).PasteSpecial xlPasteValues
'Trim the store data
For Each c In cs.Range(cs.Cells(lRow2 + 1, 3), cs.Cells(lRow2 + 1 + lRow1 - 8, 3))
c.Value = Right(c.Value, 4)
Next c
'Apply the vlookup
For Each c In cs.Range(cs.Cells(lRow2 + 1, 4), cs.Cells(lRow2 + 1 + lRow1 - 8, 4))
c.Formula = "=+VLOOKUP(C" & c.Row & ",'Walmart Table'!A:B,2,FALSE)"
Next c
ws.Activate
''''''''''''''''''''''''''''''''''''''
'Start of Slicer Looping component
For r = lRow2 + 1 To lRow2 + 1 + lRow1 - 8
wb.SlicerCaches("Slicer_Ticket_Number").VisibleSlicerItemsList = Array("[Sales].[Ticket Number].&[" & cs.Range("A" & r).Value & "]")
Application.Wait (Now + TimeValue("0:00:01")) 'This is mainly for visual satisfaction.
'Run some qualifiers before uploading
If ws.Range("D3").Value = "Does not tie-out" Then cs.Range("E" & r).Value = ws.Range("D3").Value
If ws.Range("D3").Value = "Credit memo" Then cs.Range("E" & r).Value = ws.Range("D3").Value
If ws.Range("D3").Value = "Already in WebEDI" Then cs.Range("E" & r).Value = ws.Range("D3").Value
'If no reason not to, then go ahead an upload
If ws.Range("D3").Value = "Okay to upload" Then
''''''''''''''''''''''''''''''''''''''
'Start of WebEDI component
'Open website
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.navigate ***OMMITTED***
'Let website load
While IE.ReadyState <> 4
DoEvents
Wend
'Input store value
With IE.document
.all("inputStore").Value = ws.Range("C1").Value
.all("inputStore").Focus
.all("inputStore").Select
End With
'The section only updates once it recognizes that values have been input. This seems to get force that interaction. It is definitely not best prcatice though.
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:02"))
'Finish the button clicks on the first page, giving it appropriate refresh time.
Set ElementCol = IE.document.getElementsByClassName("btn btn-primary")
ElementCol.Item(0).Click
Application.Wait (Now + TimeValue("0:00:02"))
Set ElementCol = IE.document.getElementsByClassName("btn btn-primary pull-right")
ElementCol.Item(0).Click
Application.Wait (Now + TimeValue("0:00:02"))
'Let website load
While IE.ReadyState <> 4
DoEvents
Wend
'Give IE a chance to un-stuck
Application.Wait (Now + TimeValue("0:00:03"))
'Fill in the info at the top of the page
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
With IE.document
.all("InvoiceNbr").Value = ws.Range("C3").Value
.all("invoiceDate").Value = ws.Range("C4").Value
.all("shipDate").Value = ws.Range("C5").Value
.all("InvoiceNbr").Select
End With
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:02"))
'Add the necessary number of rows
For i = 1 To ws.Range("C7").Value - 1
Set ElementCol = IE.document.getElementsByClassName("fa fa-plus fa-lg")
ElementCol.Item(0).Click
Next i
With IE.document
.querySelector("input[title='Item']").Value = 0
.querySelector("input[title='Item']").Select
End With
For i = 12 To 43
If ws.Range("B" & i).EntireRow.Hidden = False Then
Application.SendKeys ws.Range("B" & i).Value, True
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:01"))
Application.SendKeys ws.Range("C" & i).Value, True
Application.SendKeys "{Tab}", True
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:01"))
Application.SendKeys ws.Range("E" & i).Value, True
Application.SendKeys "{Tab}", True
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:01"))
Application.SendKeys ws.Range("G" & i).Value, True
Application.SendKeys "{Tab}", True
Application.SendKeys "{Tab}", True
Application.Wait (Now + TimeValue("0:00:01"))
End If
Next i
'Submit Invoice
Set ElementCol = IE.document.getElementsByClassName("fa fa-arrow-up fa-lg")
ElementCol.Item(0).Click
'Give IE a chance to un-stuck
Application.Wait (Now + TimeValue("0:00:01"))
'Let website load
While IE.ReadyState <> 4
DoEvents
Wend
'Give IE a chance to un-stuck
Application.Wait (Now + TimeValue("0:00:05"))
'Close IE
IE.Quit
Set IE = Nothing
'End of WebEDI component
''''''''''''''''''''''''''''''''''''''
cs.Range("E" & r).Value = "Uploaded!"
'Go to next ticket and repeat the evaluation sequence
End If
Next r
'End of Slicer Looping component
''''''''''''''''''''''''''''''''''''''
End Sub