При загрузке данных в Excel с веб-страниц порой оказывается, что некоторая необходимая нам информация (например, адреса электронной почты) представлена в графическом виде (текст на картинке).
Нам же, в таблице Excel, необходимо получить ту же информацию, но в текстовом виде, - т.е. каким-то образом распознать текст, изображенный на картинке.
Для этих целей существуют специальные OCR-программы (например, ABBYY FineReader, CuneiForm и т.д.), а также онлайн-сервисы (платные и бесплатные)
Поскольку нам в макросе надо распознать лишь несколько простеньких изображений, не имеет смысла устанавливать на компьютер специализированную программу OCR, - особенно с учётом того, что она стоит много денег.
Поэтому для нашей задачи мы воспользуемся бесплатным онлайн-сервисом newocr.com
Итак, изначально у нас имеется ссылка вида "http://site.ru/filename.jpeg", по которой доступна для загрузки картинка с необходимым нам текстом.
Воспользуемся функцией newOCR, чтобы получить текст с этой картинки:
Sub testOCR() link$ = "http://autotransinfo.ru/img/46e0afd12df90e69efdc931c504f24e416135037.jpeg" Text$ = newOCR(link$) MsgBox "Результат: " & Text$ End Sub
Код функции newOCR:
Function newOCR(ByVal link As String) As String On Error Resume Next Set IE = CreateObject("InternetExplorer.Application") IE.Navigate "http://www.newocr.com/" While IE.Busy Or (IE.readyState <> 4): DoEvents: Wend Set IEdoc = IE.document IE.document.getElementById("url").value = link ' вставляем ссылку на изображение IE.document.getElementById("language").value = "eng" ' выбираем язык распознавания IE.document.getElementById("preview").Click ' нажимаем предпросмотр While IE.Busy Or (IE.readyState <> 4): DoEvents: Wend Err.Raise 555: Dim n As Long While Err > 0 And n < 10000 ' ждём, пока не появится кнопка ЩСК Err.Clear: DoEvents: n = n + 1 IE.document.getElementById("ocr").Click ' жмём кнопку OCR Wend While IE.Busy Or (IE.readyState <> 4): DoEvents: Wend Err.Raise 555: n = 0 While Err > 0 And n < 100000 ' ждём, пока не появится результат распознавания Err.Clear: DoEvents: n = n + 1 newOCR = IE.document.getElementById("textarea").value ' читаем результат Wend IE.Quit End Function
PS: Функция тестировалась на картинках, содержащих адреса почты.
Пример такой картинки:
Второй вариант функции - с использованием онлайн сервиса sciweavers.org
(кстати, функция onlineOCR работает быстрее предыдущей, но, увы, ошибок распознавания вроде бы больше)
Sub test_onlineOCR() link$ = "http://autotransinfo.ru/img/46e0afd12df90e69efdc931c504f24e416135037.jpeg" Text$ = onlineOCR(link$) Debug.Print "Результат: " & Text$ End Sub Function onlineOCR(ByVal link As String) As String On Error Resume Next Set xmlhttp = CreateObject("Microsoft.XMLHTTP") xmlhttp.Open "POST", "http://www.sciweavers.org/process_form_i2ocr", "False" xmlhttp.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" ' чтобы избежать кеширования Dim POST() As Byte, PostData$ PostData = PostData & "i2ocr_options=" & RussianStringToURLEncode("url") PostData = PostData & "&i2ocr_uploadedfile=" & RussianStringToURLEncode(link) PostData = PostData & "&i2ocr_url=" & RussianStringToURLEncode(link) PostData = PostData & "&i2ocr_languages=" & RussianStringToURLEncode("gb") POST = StrConv(PostData, vbFromUnicode) xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" xmlhttp.send (POST): DoEvents If Val(xmlhttp.Status) <> 200 Then Exit Function URL2$ = Split(xmlhttp.responsetext, "$.get(""/")(1) URL2$ = "http://www.sciweavers.org/" & Split(URL2$, """, function")(0) xmlhttp.Open "GET", URL2$, "False": xmlhttp.send: DoEvents If Val(xmlhttp.Status) = 200 Then onlineOCR = xmlhttp.responsetext Set xmlhttp = Nothing End Function
Как выяснилось в результате тестирования функции onlineOCR (а тестирование проводилось на сотнях картинок типа вышеприведённой),
она хоть и работает значительно быстрее и стабильнее, но результат распознавания нельзя назвать удовлетворительным.
OnlineOCR путает такие символы, как 1, l, I, | (единица, строчная L, прописная i, вертикальная черта)
В то же время, функция newOCR работает медленно, и порой прекращает работать после нескольких распознаваний.
(требуется доработка кода - судя по всему, обращения выполняются слишком часто, и сервер даёт отказ, предлагая подождать несколько секунд)
Сделал сравнение результатов работы 2 этих онлайн-сервисов OCR:
На скриншоте зеленым помечены правильно распознанные адреса электронной почты, красным - распознанные с ошибками.
Обратите внимание - первый адрес оба сервиса распознали ошибочно (поставили ноль вместо буквы O)
Комментарии
Да, код открыт, - если делать макрос под заказ.
Вопрос о заказах макросов. Макрос Вы даёте с открытым кодом?
Касательно ПДФ - можно попробовать получить из него текст и без файнридера (если в файле ПДФ есть текстовый слой, - т.е. можно выделить текст в AdobeReader)
Код дать не смогу, - но можем сделать под заказ (у моего коллеги есть опыт получения текста из PDF)
C FineReader не работал ни разу, - так что тут ничего подсказать не могу.
Большое СПАСИБО за информацию. Подскажите, пожалуйста, как можно организовать подобным способом (т.е. автоматически через VBA) уже установленную FineReader? Имеется ФАЙЛ.pdf. Ассоциирован c AdobeReader. Не могу понять как этот файл сразу открыть в FR не меняя ассоциацию и заставить скинуть текст в VBA (ну или хотя бы просто открыть этот файл в FR). Заранее благодарен!
Добрый день!
В продолжение темы про OCR и потояннство кода - на сайте newOCR есть возможноть наладить распознование через пост запросы, при условии получения ключа они позволяют произоводить одно распознование в минуту, это мне кажется в полне нормально, вот только проблема в реализации формирования самого пост зарпоса через VBA код, т.к. там нужно указать тот самый ключ..И
(Пример на основе Вашего кода на сайт залил)
Sub ПримерОтправкиФайлаНаФайлообменник()
FileName$ = "путь к файлу/OCR.JPG"
URL$ = "http://api.newocr.com/v1/"
If Dir(FileName$, vbNormal) = "" Then ' проверяем наличие файла FileName$
MsgBox "Файл: " & FileName$ & " не найден", vbCritical, "Отправка файла невозможна!"
Exit Sub
End If
СсылкаНаЗагруженныйФайл = UploadFile(URL$, FileName$) ' пытаемся отправить файл
If Len(СсылкаНаЗагруженныйФайл) Then
MsgBox "Ссылка для скачивания: " & СсылкаНаЗагруженныйФайл, vbInformation, _
"Файл успешно загружен на файлообменник zalil.ru"
Else
MsgBox "Файл: " & FileName$, vbCritical, _
"Не удалось отправить файл на файлообменник zalil.ru"
End If
End Sub
Function UploadFile(ByVal DestURL As String, ByVal FileName As String) As String
Dim sFormData As String, d As String: On Error Resume Next
sFormData = GetFile(FileName) 'Get source file As a string.
FormData = "POST /v1/upload?key=" + ключ + " HTTP/1.1" + vbCrLf
FormData = FormData + "Host: api.newocr.com" + vbCrLf
Const Boundary As String = "---------------------------41184676334"
FormData = FormData + "Content-Type: multipart/form-data; boundary=" + Boundary + vbCrLf 'Build source form with file contents
FormData = FormData + "Content-Length: 29278" + vbCrLf + vbCrLf
FormData = FormData + "Content-Disposition: form-data; name=""" + sFormData + """;" + " filename=""" + Dir(FileName) + """" + vbCrLf
FormData = FormData + "Content-Type: image/jpeg" + vbCrLf
FormData = FormData + "(Binary data not shown)" + vbCrLf
FormData = FormData + "-----------------------------41184676334--"
MsgBox FormData
Dim WebBrowser: Set WebBrowser = CreateObject("InternetExplorer.Application") ' WebBrowser.Visible = True
'Send the form data To URL As POST request
Dim bFormData() As Byte: ReDim bFormData(Len(FormData) - 1)
bFormData = StrConv(FormData, vbFromUnicode)
WebBrowser.Navigate DestURL, , , bFormData '"Content-Type: multipart/form-data; boundary=" + Boundary + vbCrLf
Do While WebBrowser.Busy: DoEvents: Loop
UploadFile = WebBrowser.LocationURL: If UploadFile = DestURL Then UploadFile = ""
WebBrowser.Quit
End Function
Function GetFile(FileName As String) As String 'read binary file As a string value
' вспомогательная функция. Возвращает текстовую строку - файл FileName в юникоде
Dim FileContents() As Byte, FileNumber As Integer
ReDim FileContents(FileLen(FileName) - 1)
FileNumber = FreeFile
Open FileName For Binary As FileNumber
Get FileNumber, , FileContents
Close FileNumber
GetFile = StrConv(FileContents, vbUnicode)
End Function
Мы о разных методах работы. Ручками кликая на сайте, конечно подсунешь любой файл, но статья админа совсем не об этом, а об автоматизации этого процесса.
Мне кажется или первый сервис теперь движение мышки проверяет?
В чем проблема загрузки файла на первый сервис?
Зачем нужен сторонний url,когда сервис предлагает закачать любые файлы даже в формате типа pdf
Первый макрос устарел не очень сильно. Я разобрался, вместо
newOCR = ie.document.getElementById("ocr-result").value нужно использовать
newOCR = ie.document.getElementById("ocr-result").innerHtml
жаль не получается подсовывать свой локальный файл так как элемент
<@input type="file" name="userfile" id="userfile"/> имеет значение value только для чтения.
Придется отправлять файл сначала на сторонний УРЛ в сеть, а потом кидать этот УРЛ на форму.
Или есть решение?
Эти макросы очень давно устарели.
Сайты OCR так быстро меняются, что один сайт успели переделать, пока я писал и тестировал макрос)
Потом, когда макросы написал, один сайт переделали через 2 дня, второй - через месяц примерно.
Соответственно, оба макроса почти сразу перестали работать.
Самое сложное в этой задаче, - не код написать, а найти бесплатный, реально работающий, онлайн-сервис OCR
Скрипт немного устарел. Так например элемент страницы с текстом сейчас не
newOCR = IE.document.getElementById("textarea").value а
newOCR = ie.document.getElementById("ocr-result").Value
Заменил название, но результат пуст, хотя в отладке делаю ie.visible=true, (Вашу картинку кстати не распознает, я закидываю другой файл) вижу что сканирование произошло, а в переменную newOCR все равно ничего не попадает. Наверное нельзя вот так "в лоб" обратится к элементу страницы с текстом, нужен какой-то перебор в цикле, но у самого пока не получается.
Отправить комментарий