Python - Автомат c стол соскоб из комплекса HTML - PullRequest
0 голосов
/ 15 апреля 2020

Я пытаюсь автоматизировать сбор всех данных из каждой таблицы на веб-сайте и выводить каждую таблицу на вкладку в Excel.

Я использую код, доступный в настоящее время для таких вопросов, как https://www.thepythoncode.com/article/convert-html-tables-into-csv-files-in-python, https://towardsdatascience.com/web-scraping-html-tables-with-python-c9baba21059 и Python - Web Scraping HTML таблица и печать в CSV .

При использовании этого URL я изо всех сил пытаюсь получить как базовые данные, так и заголовки таблиц. Формат HTML очень плотный, что затрудняет мне извлечение таблиц в правильной структуре.

Мой текущий код:

from bs4 import BeautifulSoup as bs
from urllib.request import urlopen
import re
import html2text
import requests
import pandas as pd

USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36"
# US english
LANGUAGE = "en-US,en;q=0.5"

def get_soup(url):
    """Constructs and returns a soup using the HTML content of `url` passed"""
    # initialize a session
    session = requests.Session()
    # set the User-Agent as a regular browser
    session.headers['User-Agent'] = USER_AGENT
    # request for english content (optional)
    session.headers['Accept-Language'] = LANGUAGE
    session.headers['Content-Language'] = LANGUAGE
    # make the request
    html = session.get(url)
    # return the soup
    return bs(html.content, "html.parser")

def get_all_tables(soup):
    """Extracts and returns all tables in a soup object"""
    return soup.find_all("table")

def get_table_headers(table):
    """Given a table soup, returns all the headers"""
    headers = []
    for th in table.find("tr").find_all("th"):
        headers.append(th.text.strip())
    return headers

def get_table_rows(table):
    """Given a table, returns all its rows"""
    rows = []
    for tr in table.find_all("tr")[1:]:
        cells = []
        # grab all td tags in this table row
        tds = tr.find_all("td")
        if len(tds) == 0:
            # if no td tags, search for th tags
            # can be found especially in wikipedia tables below the table
            ths = tr.find_all("th")
            for th in ths:
                cells.append(th.text.strip())
        else:
            # use regular td tags
            for td in tds:
                cells.append(td.text.strip())
        rows.append(cells)
    return rows

def save_as_csv(table_name, headers, rows):
    pd.DataFrame(rows, columns=headers).to_csv(f"{table_name}.csv")

def main(url):
    # get the soup
    soup = get_soup(url)
    # extract all the tables from the web page
    tables = get_all_tables(soup)
    print(f"[+] Found a total of {len(tables)} tables.")
    # iterate over all tables
    for i, table in enumerate(tables, start=1):
        # get the table headers
        headers = get_table_headers(table)
        # get all the rows of the table
        rows = get_table_rows(table)
        # save table as csv file
        table_name = f"table-{i}"
        print(f"[+] Saving {table_name}")
        save_as_csv(table_name, headers, rows)

main("https://www.sec.gov/Archives/edgar/data/1701605/000170160519000089/bkr-2019093010xq.htm")

Например, мне понадобится код для идентификации таблицы, такой как на прилагаемом изображении, и размещения всей информации в формате Excel Table in URL

Код из таких вопросов, как Извлечение HTML Таблицы с похожими данными из разных источников с различным форматированием - Python и Извлечение HTML Таблица на основе спецификаций c Заголовки столбцов - Python может выполнять поиск по URL, но ищет слишком точный c критерий, так как мне нужны все таблицы в URL.

Буду признателен за любую помощь! Я уверен, что есть элегантное решение, которое я не вижу

1 Ответ

1 голос
/ 15 апреля 2020

Я посмотрел. URL в вашем сообщении в значительной степени опирается на JavaScript, чтобы заполнить страницу ее элементами. Вот почему BeautifulSoup этого не видит. Шаблон HTML имеет двенадцать таблиц, каждая из которых выглядит примерно так:

<table class="table table-striped table-sm">
    <tbody id="form-information-modal-carousel-page-1">
        <!-- Below is populated dynamically VIA JS -->
            <tr>
                <td class="text-center">
                    <i class="fas fa-spinner fa-spin"></i>
                </td>
            </tr>
    </tbody>
</table>
</div>
<div class="carousel-item table-responsive">
    <table class="table table-striped table-bordered table-sm">
        <tbody id="form-information-modal-carousel-page-2">
            <!-- Below is populated dynamically VIA JS -->
            ...

Обратите внимание на комментарии <!-- Below is populated dynamically VIA JS -->. В основном все интересные данные не заполняются в этом HTML. Я зарегистрировал свой сетевой трафик c, и страница отправляет два XHR-запроса. Один выглядел многообещающе, а именно MetaLinks.json. Он огромен, но, к сожалению, табличных данных там нет (все еще довольно интересно, может быть полезно для других вещей). Другой ресурс XHR является действительным документом HTML, который содержит данные запечатанной таблицы. JSON было бы лучше, так как нам не пришлось бы использовать BeautifulSoup для его анализа, но что угодно. Кстати, это HTML - это то, что мы действительно хотим очистить. Мы не хотим очищать предоставленный вами URL-адрес (интерактивное встроенное средство просмотра XBRL) - он фактически использует этот ресурс HTML XHR для заполнения себя. Это HTML - это то же самое, что вы видите, когда нажимаете на меню гамбургера встроенного средства просмотра XBRL в левом верхнем углу и выбираете «Открыть как HTML». Если у вас возникли проблемы с его поиском, URL-адрес: https://www.sec.gov/Archives/edgar/data/1701605/000170160519000089/bkr-2019093010xq.htm

РЕДАКТИРОВАТЬ - Вот небольшой пример. Я просто извлекаю некоторые цифры из таблиц:

def main():

    import requests
    from bs4 import BeautifulSoup

    url = "https://www.sec.gov/Archives/edgar/data/1701605/000170160519000089/bkr-2019093010xq.htm"

    response = requests.get(url, headers={})
    response.raise_for_status()

    soup = BeautifulSoup(response.content, "html.parser")

    for table in soup.find_all("table"):
        for row in table.find_all("tr"):
            for data in row.find_all("ix:nonfraction"):
                print(data.text, end=" ")
            print()
        print()


    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

Вывод:

3,339 3,142 9,886 9,421 
2,543 2,523 7,604 7,191 
5,882 5,665 17,490 16,612 


2,901 2,819 8,647 8,371 
1,880 1,873 5,705 5,491 
679 608 2,083 1,944 
71 66 183 374 
54 17 128 113 
5,585 5,383 16,746 16,293 
297 282 744 319 
14 6 124 51 
59 55 174 164 
224 233 446 206 
— 85 — 139 
107 110 269 86 
117 38 177 19 
60 25 97 83 
57 13 80 64 
...

Вывод на самом деле намного длиннее, чем я показал, но вы поняли идею , Кроме того, я не извлекаю все соответствующие числа из таблиц, так как я смотрю только на теги ix:nonfraction, но есть и другие виды (например, десятичные числа). HTML ДЕЙСТВИТЕЛЬНО плотный - вам нужно выяснить, как получить все остальные поля из каждой строки, позаботиться о не ix:nonfraction тегах, обработать пустые столбцы и т. Д. c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...