如何分割抓取的数据并将其保存为带有完整链接和说明的csv的单独列中?

时间:2019-04-08 07:45:02

标签: python selenium web-scraping beautifulsoup

我正在使用一个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.")

3 个答案:

答案 0 :(得分:2)

由于网站使用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模块的Session功能进行“混合”,复制所有HTTP标头和cookie,但是鉴于这似乎是政府站点,他们可能不会介意您正在抓取他们。

答案 1 :(得分:0)

在单独的列中编写

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")


我希望这对您有帮助

答案 2 :(得分:-1)

使用csv.writer类的换行符和定界符

您可以在此处找到示例:https://docs.python.org/3/library/csv.html#writer-objects