Как я могу разделить очищенные данные и сохранить их в отдельных столбцах в формате csv с полной ссылкой и описанием?

Я работаю над Web Scraper, который возвращает ссылки и описания объявлений о вакансиях, если они соответствуют списку ключевых слов. У меня проблема в том, что экспортируемый csv представляет собой всего одно длинное предложение, в котором ссылка и описание идут в одну строку.

Как я могу эффективно разделить описание и ссылки на два отдельных столбца? И как я могу добавить оставшуюся часть ссылки, чтобы иметь возможность щелкнуть ссылку внутри csv? Также есть ли способ избежать дублирования записей в csv?

Вот мой код:

from selenium import webdriver
import time, re, csv
from bs4 import BeautifulSoup as BS

keywords = ["KI", "AI", "Big Data", "Data", "data", "big data", 
"Analytics", "analytics", "digitalisierung", "ML",
"Machine Learning", "Daten", "Datenexperte", 
"Datensicherheitsexperte", "Analytikleistungen"]

browser = webdriver.Chrome()

url = "https://ausschreibungen.usp.gv.at/at.gv.bmdw.eproc-p/public"

browser.implicitly_wait(30)

browser.get(url)


innerHTML = browser.execute_script("return 
document.body.innerHTML")

soup = BS(browser.page_source, 'html.parser')

# browser.quit()
# print(soup.text)
tenders = soup.find('table', {'id': 'tenderlist'})
tbody = tenders.find('tbody')

browser.quit()


ausschreiben_found = []

for tr in tbody.find_all('tr'):
    ausschreiben = tr.find_all('td')
for keyword in keywords:
    for word in ausschreiben:
        if keyword in str(word):
            ausschreiben_found.append(word)
            print(ausschreiben_found)
with open("ausschreiben.csv", 'a', encoding='utf-8') as toWrite:
    fieldnames = ["Beschreibung", "Links"]
    writer = csv.writer(toWrite)
    writer.writerows(ausschreiben_found)
    # subprocess.call('./Autopilot3.py')
    print("Matched Ausschreiben have been collected.")

когда я запускаю ваш код, он создает пустой список для ausschreiben_found (или, я должен сказать, ничего не добавляется).

chitown88 08.04.2019 10:21

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

chitown88 08.04.2019 10:24

Если ничего не добавляется, не означает ли это, что совпадений не было? На днях он вернул 2 листинга, или я ошибаюсь? Не могли бы вы подробнее рассказать о XHR?

Erik D 08.04.2019 10:30

Если вы посмотрите на Ajax-запросы, которые отправляет эта страница, то увидите, что один из них заполняет таблицу данных (.../at.gv.bmdw.eproc-p/ajax/dataTablesTenderList?...). Он возвращает JSON. Вам может быть гораздо проще запросить это напрямую, чем идти через Selenium и пытаться анализировать HTML.

Tomalak 08.04.2019 10:33

Эрик, вы правы, если ничего не было добавлено, значит ничего не найдено по этим ключевым словам. Я ожидал, так как вы опубликовали это сегодня, вы получили результаты сегодня.

chitown88 08.04.2019 10:50
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
569
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Используйте параметры новой строки и разделителя класса csv.writer.

Вы можете найти примеры здесь: https://docs.python.org/3/library/csv.html#писатели-объекты

Хотя это может помочь OP, лучше добавить больше деталей, примеров и т. д. Пожалуйста, давать ответы, не требующие пояснений от спрашивающего.

Tiw 08.04.2019 11:04

писать в отдельные столбцы

reader = csv.DictReader(f) # open and write mode opened file
csvWriter = csv.writer(f)
existing_queries = set()
for row in reader:
    if reader.line_num == 1:
       continue
if row['link'] in existing_queries:
    print("Already exists")
else:
    csvWriter.writerow("description", "link") # will write
    existing_queries.add("description", "link")


надеюсь, это поможет

Ответ принят как подходящий

Поскольку веб-сайт использует Ajax и библиотеку JavaScript для заполнения таблицы на странице, самый простой способ получить нужные данные — реплицировать запрос Ajax.

Данные JSON с сервера имеют следующую структуру:

{
    "value": {
        "draw": "-1",
        "recordsTotal": 1476,
        "recordsFiltered": 1476,
        "data": [{
            "DT_RowClass": "even",
            "0": "<a href=\"/at.gv.bmdw.eproc-p/public/de_AT/tenderlist?action=view&amp;object=41a809d9-0b61-4991-86b8-74dc07973af3-15ed14df-d91c-4905-94fd-e1d7935eaef1\">Planung Freiland/Brücke</a>",
            "1": "Autobahnen- und Schnellstraßen-Finanzierungs-Aktiengesellschaft",
            "2": "08.04.2019",
            "3": null
        }, {
            "DT_RowClass": "odd",
            "0": "<a href=\"/at.gv.bmdw.eproc-p/public/de_AT/tenderlist?action=view&amp;object=86dd87bd-7426-40c5-946b-62b2af638aab-7a54478b-9e89-4d47-bdf8-dc8b867c57b8\">Lieferung von Erdgas 2020 - 2022</a>",
            "1": "Republik Österreich (Bund), Bundesbeschaffung GmbH sowie alle weiteren Auftraggeber gemäß der den Ausschreibungsunterlagen beiliegenden Drittkundenliste, im Vergabeverfahren alle vertreten durch die Bundesbeschaffung GmbH",
            "2": "08.04.2019",
            "3": "07.05.2019"
        }]
    }
}

Далее используется модуль requests для получения JSON с сервера и самый маленький анализатор HTML для извлечения текста из ссылок. Вы можете использовать BeautifulSoup для той же цели.

import requests
from html.parser import HTMLParser

class TinyTextExtractor(HTMLParser):
    def parse(self, html):
        self.text = ''
        self.feed(html)
        return self.text

    def handle_data(self, data):
        self.text += data

def get_ausschreibungen(start=0, length=25):
    url = 'https://ausschreibungen.usp.gv.at/at.gv.bmdw.eproc-p/ajax/dataTablesTenderList'
    resp = requests.get(url, {
        'start': start,
        'length': length
    })

    parser = TinyTextExtractor()

    for row in resp.json()['value']['data']:
        yield {
            'Bezeichnung': parser.parse(row['0']),
            'Organisation': row['1'],
            'Veröffentlicht':  row['2'],
            'Frist': row['3'],
        }

Применение:

for item in get_ausschreibungen(0, 3):
    print(item)

Что печатает это для меня:

{'Bezeichnung': 'Planung Freiland/Brücke', 'Organisation': 'Autobahnen- und Schnellstraßen-Finanzierungs-Aktiengesellschaft', 'Veröffentlicht': '08.04.2019', 'Frist': None}
{'Bezeichnung': 'Lieferung von Erdgas 2020 - 2022', 'Organisation': 'Republik Österreich (Bund), Bundesbeschaffung GmbH sowie alle weiteren Auftraggeber gemäß der den Ausschreibungsunterlagen beiliegenden Drittkundenliste, im Vergabeverfahren alle vertreten durch die Bundesbeschaffung GmbH', 'Veröffentlicht': '08.04.2019', 'Frist': '07.05.2019'}
{'Bezeichnung': 'Umbau Bahnhof Villach ', 'Organisation': 'ÖBB-Personenverkehr AG', 'Veröffentlicht': '08.04.2019', 'Frist': None}

Я уверен, что фильтрация/превращение его в CSV больше не проблема.

Используйте инструменты разработчика браузера (F12), чтобы выяснить, какие другие параметры запроса отправляются и имеют ли они отношение к вам. Вы также можете попробовать «вписаться», используя функцию сеанса модуля requests, реплицируя все заголовки HTTP и файлы cookie, но, учитывая, что это правительственный сайт, они, вероятно, не будут возражать, что вы их очищаете.

Большое спасибо за это! Не понимал, что могу использовать запрос Ajax для анализа данных :)

Erik D 08.04.2019 13:42

Есть ли способ разобрать ссылку href?

Erik D 08.04.2019 13:58

Как я уже сказал, вы можете использовать BeautifulSoup для разбора строки в row['0']. Поскольку в первом столбце может быть более сложный HTML, чем просто единственное число <a>, это в любом случае хорошая идея.

Tomalak 08.04.2019 14:06

Также есть способ расширить мой «наименьший парсер HTML» для этого, если вы представляете себе вызов, вы можете попробовать сделать это (прочитайте модуль html.parser, подсказка: вам нужно написать метод handle_starttag). Наградой будет то, что он, вероятно, немного быстрее, чем более тяжелый BeautifulSoup, и что вы научитесь работать с парсерами, основанными на событиях. :)

Tomalak 08.04.2019 14:11

Другие вопросы по теме