Страницы

Поиск по вопросам

четверг, 11 июля 2019 г.

Парсер HTML в python

Доброго времени суток!
Возникла необходимость получить данные из отчета рабочей программы, отчет в HTML.
Собственно HTML документ(Выкладываю только блок где находятся необходимые данные, если нужно дополнительно залью весь файл):
РАЗМЕРЫ:  377.000 x 77.000 mm  ПОВЕРХНОСТЬ:  29029.00 mm2  ИМЯ СВОДА ПРАВИЛ:  5P  НОМЕР ПОДПРОГРАММЫ:  SP1DOR_SHEST_BR6 / SP3DOR_SHEST_BR6  ВРЕМЯ ОБРАБОТКИ: 
Установил модуль Beautiful Soup, немного почитал документацию и написал следующий скрипт:
#!/usr/bin/env python # -*- coding: utf-8 -*- from bs4 import BeautifulSoup f = open('File1.HTML', 'rb') doc = f.read() soup = BeautifulSoup(doc) rez = [] for x in soup.find_all('font', size="2"): rez.append(x.contents[0]) if x.contents[0] == 'ВЕС: ': #Велосипед для ограничения выхода из диапазона break inp = [] for y in range(1000): if str(rez[y]) == 'НОМЕР ЧЕРТЕЖА: ': inp.append([rez[y], rez[y+1]]) print(inp)
Очень всё шатко, и ограничение по циклу, будет работать если у меня отчет на одно изделие. Идея в том, что получить данные из всех font, затем прогнать результат в цикле и найти с помощью If-ов необходимые данные, для примера допустим нужно извлечь поле "РАЗМЕРЫ: " и соответственно значение этого поля "377.000 x 77.000 mm ".

Сомнительный результат, поэтому не могли бы вы подсказать как это лучше реализовать?
Полный HTML файл(оформлен ужасно):


TruTops Laser - ПЛАН НАЛАДКИ / TruLaser 3030 (L20) - 1 / DOR_SHEST_BR6


E:/Templates/HTML/SYSTEM_Logo.gif ПЛАН НАЛАДКИ
ОБЩИЕ ПАРАМЕТРЫ 
Antonov 
25.08.2015
TruTops Laser V10.00.00











ИНФОРМАЦИЯ ОБ ОТД. ДЕТАЛИ 
НОМЕР ДЕТАЛИ: 
НОМЕР ЧЕРТЕЖА: 425900-92.08.101 
ИМЯ ЧЕРТЕЖА:  
ЗАКАЗЧИКА:  
КОЛИЧЕСТВО: 
РАЗМЕРЫ: 377.000 x 77.000 mm 
ПОВЕРХНОСТЬ: 29029.00 mm2 
ИМЯ СВОДА ПРАВИЛ: 5P 
НОМЕР ПОДПРОГРАММЫ: SP1DOR_SHEST_BR6 / SP3DOR_SHEST_BR6 
ВРЕМЯ ОБРАБОТКИ: 0.47 min (PierceLine: 0.47 min) 
ДЛИНА РЕЗКИ: 1241.13 mm 
ВЕС: 1.823 kg 
КОЛ-ВО ТОЧЕК ВРЕЗАНИЯ: 
ВРЕМЯ ВРЕЗАНИЯ 0.17 (PierceLine: 0.06) s 
ИМЯ ГЕОМ. ФАЙЛА: D:\Programs TRUMPF\2015\№101 Крой изделия 425901-92.00.010-10 (доп.1)\Крой ч10\425900-92.08.101.GEO 
ПРЕДВ. НАЧЕРЧ. РАЗМЕТКА:SP1DOR_SHEST_BR6 - 0.13 min
НОМЕР ДЕТАЛИ: 
НОМЕР ЧЕРТЕЖА: 425900-92.08.102 
ИМЯ ЧЕРТЕЖА:  
ЗАКАЗЧИКА:  
КОЛИЧЕСТВО: 
РАЗМЕРЫ: 264.000 x 77.000 mm 
ПОВЕРХНОСТЬ: 20328.00 mm2 
ИМЯ СВОДА ПРАВИЛ: 5P 
НОМЕР ПОДПРОГРАММЫ: SP2DOR_SHEST_BR6 / SP4DOR_SHEST_BR6 
ВРЕМЯ ОБРАБОТКИ: 0.42 min (PierceLine: 0.42 min) 
ДЛИНА РЕЗКИ: 1023.53 mm 
ВЕС: 1.277 kg 
КОЛ-ВО ТОЧЕК ВРЕЗАНИЯ: 
ВРЕМЯ ВРЕЗАНИЯ 0.17 (PierceLine: 0.06) s 
ИМЯ ГЕОМ. ФАЙЛА: D:\Programs TRUMPF\2015\№101 Крой изделия 425901-92.00.010-10 (доп.1)\Крой ч10\425900-92.08.102.GEO 
ПРЕДВ. НАЧЕРЧ. РАЗМЕТКА:SP2DOR_SHEST_BR6 - 0.15 min










Ответ

Можно воспользоваться тем, что все детали определены в одной таблице. В этом файле такая таблица находится однозначно с помощью поиска:
table = soup.find('table', width="600", border="1", cellspacing="1", cellpadding="0")
Далее можно выбрать все строки таблицы с помощью поиска
trs = list(table.find_all('tr'))
Для удобства итерации я преобразовал результат поиска в список. Использовал то, что поля в таблице идут в одном и том же порядке и в последовательных строках. Всего таких строк 15.
Осталась задача найти начало записи, после чего её уже разобрать. Начало записи обозначается строкой таблицы, содержащей строку 'НОМЕР ДЕТАЛИ:'. Для простоты кода я использовал цикл for, но при желании можно использовать ручную итерацию. Возможно, она будет работать немного быстрее.
Также заметил, что на странице используются неразрывные пробелы. Они имеют код \xa0. Я их преобразовываю в обычные, при желании можно их убрать, на исполнение скрипта это не влияет.
Далее разбор строк. Каждая интересующая нас строка состоит из двух элементов. Первый отвечает за имя, второй -- за значение. Пробегаюсь по всем этим строкам и сохраняю почищенные значения в кортеж.
Вот полный код скрипта:
from bs4 import BeautifulSoup
def clear_string(s): return s.replace('\xa0', ' ').strip()
def parse_detail(detail_rows): return tuple(tuple(clear_string(text) for text in row.strings) for row in detail_rows)
start_row_name = 'НОМЕР ДЕТАЛИ:' rows_count = 15
with open('File1.HTML') as in_file: soup = BeautifulSoup(in_file.read())
table = soup.find('table', width="600", border="1", cellspacing="1", cellpadding="0") trs = list(table.find_all('tr'))
details = [] for i, tr in enumerate(trs): strings = tuple(clear_string(text) for text in tr.strings) if len(strings) == 2 and strings[0] == start_row_name: details.append(parse_detail(trs[i : i + rows_count]))
print(details)
Результат работы скрипта на представленной странице:
# [(('НОМЕР ДЕТАЛИ:', '1'), # ('НОМЕР ЧЕРТЕЖА:', '425900-92.08.101'), # ('ИМЯ ЧЕРТЕЖА:', ''), # ('ЗАКАЗЧИКА:', ''), # ('КОЛИЧЕСТВО:', '4'), # ('РАЗМЕРЫ:', '377.000 x 77.000 mm'), # ('ПОВЕРХНОСТЬ:', '29029.00 mm2'), # ('ИМЯ СВОДА ПРАВИЛ:', '5P'), # ('НОМЕР ПОДПРОГРАММЫ:', 'SP1DOR_SHEST_BR6 / SP3DOR_SHEST_BR6'), # ('ВРЕМЯ ОБРАБОТКИ:', '0.47 min (PierceLine: 0.47 min)'), # ('ДЛИНА РЕЗКИ:', '1241.13 mm'), # ('ВЕС:', '1.823 kg'), # ('КОЛ-ВО ТОЧЕК ВРЕЗАНИЯ:', '1'), # ('ВРЕМЯ ВРЕЗАНИЯ', '0.17 (PierceLine: 0.06) s'), # ('ИМЯ ГЕОМ. ФАЙЛА:', # 'D:\\Programs TRUMPF\\2015\\№101 Крой изделия 425901-92.00.010-10 ' # '(доп.1)\\Крой ч10\\425900-92.08.101.GEO')), # (('НОМЕР ДЕТАЛИ:', '2'), # ('НОМЕР ЧЕРТЕЖА:', '425900-92.08.102'), # ('ИМЯ ЧЕРТЕЖА:', ''), # ('ЗАКАЗЧИКА:', ''), # ('КОЛИЧЕСТВО:', '4'), # ('РАЗМЕРЫ:', '264.000 x 77.000 mm'), # ('ПОВЕРХНОСТЬ:', '20328.00 mm2'), # ('ИМЯ СВОДА ПРАВИЛ:', '5P'), # ('НОМЕР ПОДПРОГРАММЫ:', 'SP2DOR_SHEST_BR6 / SP4DOR_SHEST_BR6'), # ('ВРЕМЯ ОБРАБОТКИ:', '0.42 min (PierceLine: 0.42 min)'), # ('ДЛИНА РЕЗКИ:', '1023.53 mm'), # ('ВЕС:', '1.277 kg'), # ('КОЛ-ВО ТОЧЕК ВРЕЗАНИЯ:', '1'), # ('ВРЕМЯ ВРЕЗАНИЯ', '0.17 (PierceLine: 0.06) s'), # ('ИМЯ ГЕОМ. ФАЙЛА:', # 'D:\\Programs TRUMPF\\2015\\№101 Крой изделия 425901-92.00.010-10 ' # '(доп.1)\\Крой ч10\\425900-92.08.102.GEO'))]

Комментариев нет:

Отправить комментарий