diff --git a/.gitignore b/.gitignore
index b26f8f11..d2f92306 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@ dev_data_folder*
.idea/
.cache/
data/
+tools/report_generator/reports/
+tools/crawl_summary/crawl_data/
*.pyc
*.egg-info
diff --git a/requirements.txt b/requirements.txt
index 7c1b26f6..bc1b61df 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -48,6 +48,11 @@ git+https://github.com/zeeguu/confusionwords.git@main#egg=confusionwords
scikit-learn==1.4.0
flask_monitoringdashboard
+# For the report generator
+matplotlib
+seaborn
+pandas
+
# the following two were required when deploying the API on Mac OS with Python 3.12.1
cryptography
lxml_html_clean
diff --git a/tools/add_feed.py b/tools/add_feed.py
index d71b6088..a1c839cd 100644
--- a/tools/add_feed.py
+++ b/tools/add_feed.py
@@ -28,8 +28,8 @@ def main():
print(f"= {icon_name}")
description = (
- input(f"Description (Enter for: {test_feed.description}): ")
- or test_feed.description
+ input(f"Description (Enter for: {test_feed.description}): ")
+ or test_feed.description
)
print(f"= {description}")
@@ -46,7 +46,7 @@ def main():
description,
icon_name=icon_name,
language=language,
- feed_type=feed_type
+ feed_type=feed_type,
)
print("Done: ")
diff --git a/tools/crawl_summary/__init__.py b/tools/crawl_summary/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tools/crawl_summary/crawl_report.py b/tools/crawl_summary/crawl_report.py
new file mode 100644
index 00000000..9d4a0247
--- /dev/null
+++ b/tools/crawl_summary/crawl_report.py
@@ -0,0 +1,226 @@
+from collections import Counter
+import datetime
+import os
+import inspect
+import json
+import pathlib
+
+STR_DATETIME_FORMAT = "%d_%m_%y_%H_%M_%S"
+CRAWL_REPORT_DATA = os.environ.get(
+ "CRAWL_REPORT_DATA",
+ os.path.join(pathlib.Path(__file__).parent.resolve(), "crawl_data"),
+)
+
+
+class CrawlReport:
+ def __init__(self) -> None:
+ self.save_dir = CRAWL_REPORT_DATA
+ self.data = {"lang": {}}
+ self.crawl_report_date = datetime.datetime.now()
+
+ def get_days_from_crawl_report_date(self):
+ return (datetime.datetime.now() - self.crawl_report_date).days
+
+ def __convert_str_to_dt(self, str_datetime):
+ dt_parsed = datetime.datetime.strptime(str_datetime, STR_DATETIME_FORMAT)
+ return dt_parsed
+
+ def __convert_dt_to_str(self, datetime):
+ return datetime.strftime(STR_DATETIME_FORMAT)
+
+ def _get_feed_dict(self, feed):
+ lang_code = feed.language.code
+ feed_id = feed.id
+ return self.data["lang"][lang_code]["feeds"][feed_id]
+
+ def add_language(self, lang_code: str):
+ self.data["lang"][lang_code] = {"feeds": {}, "total_time": None}
+
+ def add_feed(self, feed):
+ lang_code = feed.language.code
+ feed_id = feed.id
+ if lang_code not in self.data["lang"]:
+ self.add_language(lang_code)
+ self.data["lang"][lang_code]["feeds"][feed_id] = {
+ "article_report": {
+ "sents_removed": {},
+ "quality_error": {},
+ "quality_to_url": {},
+ "sents_to_url": {},
+ },
+ "last_article_date": None,
+ "feed_errors": [],
+ "crawl_time": None,
+ "total_articles": None,
+ "total_downloaded": None,
+ "total_low_quality": None,
+ "total_in_db": None,
+ }
+
+ def set_total_time(self, lang_code: str, total_time):
+ self.data["lang"][lang_code]["total_time"] = total_time
+
+ def add_feed_error(self, feed, error: str):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["feed_errors"].append(error)
+
+ def set_feed_crawl_time(self, feed, crawl_time):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["crawl_time"] = crawl_time
+
+ def set_feed_last_article_date(self, feed, last_article_date):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["last_article_date"] = self.__convert_dt_to_str(last_article_date)
+
+ def set_feed_total_articles(self, feed, total_articles):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["total_articles"] = total_articles
+
+ def set_feed_total_downloaded(self, feed, total_downloaded):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["total_downloaded"] = total_downloaded
+
+ def set_feed_total_low_quality(self, feed, total_low_quality):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["total_low_quality"] = total_low_quality
+
+ def set_feed_total_in_db(self, feed, total_in_db):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["total_in_db"] = total_in_db
+
+ def set_non_quality_reason(self, feed, non_quality_reason_counts: dict):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["article_report"]["quality_error"] = Counter(
+ non_quality_reason_counts
+ )
+
+ def set_sent_removed(self, feed, sent_removed_count: dict):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["article_report"]["sents_removed"] = Counter(sent_removed_count)
+
+ def add_non_quality_reason(self, feed, non_quality_reason, url=None):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["article_report"]["quality_error"][non_quality_reason] = (
+ feed_dict["article_report"]["quality_error"].get(non_quality_reason, 0) + 1
+ )
+ if url is not None:
+ feed_dict["article_report"]["quality_to_url"][non_quality_reason] = (
+ feed_dict["article_report"]["quality_to_url"].get(
+ non_quality_reason, []
+ )
+ + [url]
+ )
+
+ def add_sent_removed(self, feed, sent_removed, url=None):
+ feed_dict = self._get_feed_dict(feed)
+ feed_dict["article_report"]["sents_removed"][sent_removed] = (
+ feed_dict["article_report"]["sents_removed"].get(sent_removed, 0) + 1
+ )
+ if url is not None:
+ feed_dict["article_report"]["sents_to_url"][sent_removed] = feed_dict[
+ "article_report"
+ ]["sents_to_url"].get(sent_removed, []) + [url]
+
+ def save_crawl_report(self):
+ timestamp_str = self.__convert_dt_to_str(self.crawl_report_date)
+ if not os.path.exists(self.save_dir):
+ os.mkdir(self.save_dir)
+ for lang in self.data["lang"]:
+ filename = f"{lang}-crawl-{timestamp_str}.json"
+ output_dir = os.path.join(self.save_dir, lang)
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
+ with open(os.path.join(output_dir, filename), "w", encoding="utf-8") as f:
+ json.dump(self.data["lang"][lang], f)
+
+ def load_crawl_report_data(self, day_period: int, report_dir_path=None):
+ if report_dir_path is None:
+ report_dir_path = self.save_dir
+ for lang in os.listdir(report_dir_path):
+ for file in os.listdir(os.path.join(report_dir_path, lang)):
+ lang, _, date = file.split(".")[0].split("-")
+ date = self.__convert_str_to_dt(date)
+
+ day_diff = (date.now() - date).days
+ if day_diff > day_period:
+ print(
+ f"File '{file}' outside of day range of '{day_period}', was: '{day_diff}'"
+ )
+ continue
+ try:
+ self.crawl_report_date = min(self.crawl_report_date, date)
+ with open(
+ os.path.join(report_dir_path, lang, file), "r", encoding="utf-8"
+ ) as f:
+ loaded_data = json.load(f)
+ if lang not in self.data["lang"]:
+ self.add_language(lang)
+ lang_dict = self.data["lang"][lang]
+ for feed in loaded_data["feeds"]:
+ if feed not in lang_dict["feeds"]:
+ # We have not loaded any feeds yet:
+ lang_dict["feeds"][feed] = loaded_data["feeds"][feed]
+ else:
+ feed_dict = lang_dict["feeds"][feed]
+ feed_dict["article_report"]["sents_removed"] = Counter(
+ feed_dict["article_report"]["sents_removed"]
+ ) + Counter(
+ loaded_data["feeds"][feed]["article_report"][
+ "sents_removed"
+ ]
+ )
+ feed_dict["article_report"]["quality_error"] = Counter(
+ feed_dict["article_report"]["quality_error"]
+ ) + Counter(
+ loaded_data["feeds"][feed]["article_report"][
+ "quality_error"
+ ]
+ )
+ print(f"LOADED File (d:{date}, l:{lang}): {file}")
+ except Exception as e:
+ print(f"Failed to load: '{file}', with: '{e} ({type(e)})'")
+
+ def __validate_lang(self, lang: str):
+ langs_available = set(self.data["lang"].keys())
+ if lang not in langs_available:
+ raise ValueError(
+ f"'{lang}' is not found in current loaded data. Available langs: '{list(langs_available)}'"
+ )
+ return True
+
+ def get_total_non_quality_counts(self, langs_to_load: list[str] = None):
+ if langs_to_load is None:
+ langs_to_load = self.data["lang"].keys()
+ else:
+ for lang in langs_to_load:
+ self.__validate_lang(lang)
+
+ total_counts = Counter()
+ for lang in langs_to_load:
+ for feed in self.data["lang"][lang]["feeds"]:
+ feed_dict = self.data["lang"][lang]["feeds"][feed]
+ total_counts += Counter(feed_dict["article_report"]["quality_error"])
+ return total_counts
+
+ def get_total_removed_sents_counts(self, langs_to_load: list[str] = None):
+ if langs_to_load is None:
+ langs_to_load = self.data["lang"].keys()
+ else:
+ for lang in langs_to_load:
+ self.__validate_lang(lang)
+ total_counts = Counter()
+
+ for lang in langs_to_load:
+ for feed in self.data["lang"][lang]["feeds"]:
+ feed_dict = self.data["lang"][lang]["feeds"][feed]
+ try:
+ total_counts += Counter(
+ feed_dict["article_report"]["sents_removed"]
+ )
+ except Exception as e:
+ from pprint import pprint
+
+ pprint(feed_dict)
+ print(e, type(e))
+ input("Continue?")
+ return total_counts
diff --git a/tools/feed_retrieval.py b/tools/feed_retrieval.py
index 72146e12..9169610a 100755
--- a/tools/feed_retrieval.py
+++ b/tools/feed_retrieval.py
@@ -19,6 +19,7 @@
import traceback
from sqlalchemy.exc import PendingRollbackError
+from time import time
import zeeguu.core
@@ -27,17 +28,19 @@
from zeeguu.core.content_retriever.article_downloader import download_from_feed
from zeeguu.core.model import Feed, Language
+from crawl_summary.crawl_report import CrawlReport
db_session = zeeguu.core.model.db.session
-def download_for_feeds(list_of_feeds):
+def download_for_feeds(list_of_feeds, crawl_report):
summary_stream = ""
counter = 0
all_feeds_count = len(list_of_feeds)
for feed in list_of_feeds:
+ crawl_report.add_feed(feed)
if feed.deactivated:
continue
@@ -48,7 +51,12 @@ def download_for_feeds(list_of_feeds):
log(f"{msg}")
summary_stream += (
- download_from_feed(feed, zeeguu.core.model.db.session) + "\n\n"
+ download_from_feed(
+ feed,
+ zeeguu.core.model.db.session,
+ crawl_report,
+ )
+ + "\n\n"
)
except PendingRollbackError as e:
@@ -57,27 +65,50 @@ def download_for_feeds(list_of_feeds):
"Something went wrong and we had to rollback a transaction; following is the full stack trace:"
)
traceback.print_exc()
+ crawl_report.add_feed_error(feed, str(e))
- except:
+ except Exception as e:
traceback.print_exc()
+ crawl_report.add_feed_error(feed, str(e))
logp(f"Successfully finished processing {counter} feeds.")
return summary_stream
def retrieve_articles_for_language(language_code, send_email=False):
+
+ start_time = time()
language = Language.find(language_code)
all_language_feeds = (
Feed.query.filter_by(language_id=language.id).filter_by(deactivated=False).all()
)
+ crawl_report = CrawlReport()
+ crawl_report.add_language(language_code)
+
+ summary_stream = download_for_feeds(all_language_feeds, crawl_report)
+ if send_email:
+
+ logp("sending summary email")
- summary_stream = download_for_feeds(all_language_feeds)
+ import datetime
+
+ mailer = ZeeguuMailer(
+ f"{language.name} Crawl Summary "
+ + datetime.datetime.now().strftime("%H:%M"),
+ summary_stream,
+ "zeeguu.team@gmail.com",
+ )
+ mailer.send()
+ crawl_report.set_total_time(language.code, round(time() - start_time, 2))
+ crawl_report.save_crawl_report()
+ return crawl_report
def retrieve_articles_from_all_feeds():
- counter = 0
all_feeds = Feed.query.all()
- download_for_feeds(all_feeds)
+ crawl_report = CrawlReport()
+ download_for_feeds(all_feeds, crawl_report)
+ crawl_report.save_crawl_report()
if __name__ == "__main__":
diff --git a/tools/migrations/24-07-01--add_article_broken_code_map.sql b/tools/migrations/24-07-01--add_article_broken_code_map.sql
new file mode 100644
index 00000000..4050f22c
--- /dev/null
+++ b/tools/migrations/24-07-01--add_article_broken_code_map.sql
@@ -0,0 +1,6 @@
+CREATE TABLE `zeeguu_test`.`article_broken_code_map` (
+ `article_id` INT NOT NULL,
+ `broken_code` VARCHAR(45) NULL,
+ INDEX `article_broken_code_map_ibfk_1_idx` (`article_id` ASC) VISIBLE,
+ CONSTRAINT `article_broken_code_map_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `zeeguu_test`.`article` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
+);
\ No newline at end of file
diff --git a/tools/report_generator/__init__.py b/tools/report_generator/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tools/report_generator/data_extractor.py b/tools/report_generator/data_extractor.py
new file mode 100644
index 00000000..ee876181
--- /dev/null
+++ b/tools/report_generator/data_extractor.py
@@ -0,0 +1,219 @@
+import pandas as pd
+
+
+def ms_to_mins(ms_time):
+ return ms_time / 1000 / 60
+
+
+class DataExtractor:
+ def __init__(self, db_connection, DAYS_FOR_REPORT=7) -> None:
+ self.DAYS_FOR_REPORT = DAYS_FOR_REPORT
+ self.db_connection = db_connection
+
+ def __add_feed_name(self, df, feed_df, column_with_id="feed_id"):
+ df["Feed Name"] = df[column_with_id].apply(
+ lambda x: (
+ "No Feed"
+ if pd.isna(x)
+ else str(x) + " " + feed_df.loc[feed_df.id == x, "title"].values[0][:15]
+ )
+ )
+
+ def run_query(self, query):
+ df = pd.read_sql(query, con=self.db_connection)
+ return df
+
+ def get_article_topics_df(self, feed_df):
+ print("Getting Article Topics...")
+ query = f"""SELECT a.id, l.name Language, a.feed_id, t.title Topic
+ FROM article a
+ INNER JOIN article_topic_map atm on a.id = atm.article_id
+ INNER JOIN topic t ON atm.topic_id = t.id
+ INNER JOIN language l ON l.id = a.language_id
+ WHERE DATEDIFF(CURDATE(), a.published_time) <= {self.DAYS_FOR_REPORT}
+ AND a.broken = 0"""
+ df = pd.read_sql(query, con=self.db_connection)
+ self.__add_feed_name(df, feed_df)
+ return df
+
+ def get_article_df(self, feed_df):
+ print("Getting Articles...")
+ query = f"""SELECT a.*, l.name Language
+ FROM article a
+ INNER JOIN language l ON l.id = a.language_id
+ WHERE DATEDIFF(CURDATE(), published_time) <= {self.DAYS_FOR_REPORT}
+ AND a.broken = 0"""
+ df = pd.read_sql(query, con=self.db_connection)
+ self.__add_feed_name(df, feed_df)
+ return df
+
+ def get_language_df(self):
+ print("Getting Languages...")
+ query = "SELECT * from language"
+ return pd.read_sql(query, con=self.db_connection)
+
+ def get_feed_df(self):
+ print("Getting Feeds...")
+ query = """SELECT f.*,l.name Language
+ FROM feed f
+ INNER JOIN language l ON f.language_id = l.id
+ """
+ feed_pd = pd.read_sql(query, con=self.db_connection)
+ feed_pd["Feed Name"] = (
+ feed_pd["id"].astype(str) + " " + feed_pd["title"].str[:15]
+ )
+ return pd.read_sql(query, con=self.db_connection)
+
+ def get_user_reading_activity(self, language_df, feed_df):
+ print("Getting user activity...")
+ query = f"""SELECT a.id, a.language_id, a.feed_id, urs.user_id, SUM(urs.duration) total_reading_time
+ FROM article a
+ INNER JOIN user_reading_session urs ON urs.article_id = a.id
+ INNER JOIN user u ON urs.user_id = u.id
+ WHERE DATEDIFF(CURDATE(), urs.start_time) <= {self.DAYS_FOR_REPORT}
+ AND u.learned_language_id = a.language_id
+ GROUP BY a.id, a.language_id, a.feed_id, urs.user_id"""
+ reading_time_df = pd.read_sql(query, con=self.db_connection)
+ # Add the Language Name
+ reading_time_df["Language"] = reading_time_df.language_id.apply(
+ lambda x: language_df.loc[language_df.id == x, "name"].values[0]
+ )
+ # Add the Source Names
+ reading_time_df["Feed Name"] = "No Feed"
+ valid_feed_mask = ~reading_time_df["feed_id"].isna()
+ reading_time_df.loc[valid_feed_mask, "Feed Name"] = reading_time_df.loc[
+ valid_feed_mask, "feed_id"
+ ].apply(lambda x: feed_df.loc[feed_df.id == x, "title"].values[0])
+ reading_time_df.loc[valid_feed_mask, "Feed Name"] = (
+ reading_time_df.loc[valid_feed_mask].feed_id.apply(int).astype(str)
+ + " "
+ + reading_time_df.loc[valid_feed_mask, "Feed Name"].str[:15]
+ )
+ reading_time_df["total_reading_time"] = reading_time_df[
+ "total_reading_time"
+ ].apply(ms_to_mins)
+ return reading_time_df
+
+ def get_exercise_type_activity(self):
+ print("Getting Exercise Type Activity...")
+ query = f"""SELECT l.name as Language, es.source as Source, sum(e.solving_speed) total_exercise_time, Count(*) total_exercises
+ FROM user u
+ INNER JOIN user_exercise_session ues ON ues.user_id = u.id
+ INNER JOIN exercise e ON e.session_id = ues.id
+ INNER JOIN bookmark_exercise_mapping bem ON e.id = bem.exercise_id
+ INNER JOIN bookmark b ON b.id = bem.bookmark_id AND b.user_id = u.id
+ INNER JOIN user_word uw ON b.origin_id = uw.id
+ INNER JOIN exercise_source es on es.id = e.source_id
+ INNER JOIN language l on uw.language_id = l.id and uw.language_id = u.learned_language_id
+ WHERE DATEDIFF(CURDATE(), ues.last_action_time) <= {self.DAYS_FOR_REPORT}
+ GROUP BY u.learned_language_id, es.source"""
+ total_exercise_activity = pd.read_sql(query, con=self.db_connection)
+ total_exercise_activity["total_exercise_time"] = total_exercise_activity[
+ "total_exercise_time"
+ ].apply(ms_to_mins)
+ return total_exercise_activity
+
+ def get_user_exercise_activity(self):
+ print("Getting User Exercise Activity...")
+ query = f"""SELECT u.id user_id, l.name Language, sum(e.solving_speed) total_exercise_time
+ FROM user u
+ INNER JOIN user_exercise_session ues ON ues.user_id = u.id
+ INNER JOIN exercise e ON e.session_id = ues.id
+ INNER JOIN bookmark_exercise_mapping bem ON e.id = bem.exercise_id
+ INNER JOIN bookmark b ON b.id = bem.bookmark_id AND b.user_id = u.id
+ INNER JOIN user_word uw ON b.origin_id = uw.id
+ INNER JOIN exercise_source es on es.id = e.source_id
+ INNER JOIN language l on uw.language_id = l.id and uw.language_id = u.learned_language_id
+ WHERE DATEDIFF(CURDATE(), ues.last_action_time) <= {self.DAYS_FOR_REPORT}
+ GROUP BY u.id;"""
+ total_user_exercise_activity = pd.read_sql(query, con=self.db_connection)
+ total_user_exercise_activity["total_exercise_time"] = (
+ total_user_exercise_activity["total_exercise_time"].apply(ms_to_mins)
+ )
+ return total_user_exercise_activity
+
+ def get_bookmark_df(self):
+ print("Getting Bookmarks...")
+ query = f"""SELECT b.*, l.name Language, MAX(bem.exercise_id) as last_exercise, COUNT(bem.exercise_id) total_exercises
+ FROM bookmark b
+ LEFT JOIN
+ bookmark_exercise_mapping bem on b.id = bem.bookmark_id
+ INNER JOIN user_word uw ON b.origin_id = uw.id
+ INNER JOIN language l ON uw.language_id = l.id
+ WHERE DATEDIFF(CURDATE(), b.time) <= {self.DAYS_FOR_REPORT}
+ GROUP by b.id;
+ """
+ bookmarks = pd.read_sql(query, con=self.db_connection)
+ bookmarks["Has Exercised"] = bookmarks.last_exercise.apply(
+ lambda x: "No" if pd.isna(x) else "Yes"
+ )
+ return bookmarks
+
+ def get_combined_user_reading_exercise_activity(
+ self, pd_exercise_activity, pd_reading_activity
+ ):
+ user_reading_activity = (
+ pd_reading_activity.groupby(["Language", "user_id"])
+ .total_reading_time.sum()
+ .reset_index()
+ )
+ combined_exercise_reading_user = pd_exercise_activity[
+ ["user_id", "Language", "total_exercise_time"]
+ ].merge(user_reading_activity, on="user_id", how="outer")
+ combined_exercise_reading_user["Language"] = combined_exercise_reading_user[
+ "Language_y"
+ ]
+ combined_exercise_reading_user.loc[
+ combined_exercise_reading_user["Language"].isna(), "Language"
+ ] = combined_exercise_reading_user.loc[
+ combined_exercise_reading_user["Language"].isna(), "Language_x"
+ ]
+ combined_exercise_reading_user.loc[
+ combined_exercise_reading_user["total_reading_time"].isna(),
+ "total_reading_time",
+ ] = 0
+
+ combined_exercise_reading_user.loc[
+ combined_exercise_reading_user["total_exercise_time"].isna(),
+ "total_exercise_time",
+ ] = 0
+
+ active_users_reading_or_exercises = combined_exercise_reading_user[
+ (combined_exercise_reading_user["total_reading_time"] > 1)
+ | (combined_exercise_reading_user["total_exercise_time"] > 1)
+ ]
+ return active_users_reading_or_exercises
+
+ def get_topic_reading_time(self):
+ print("Getting Topic Reading Times...")
+ query = f"""SELECT l.name as Language, t.title Topic, SUM(urs.duration) total_reading_time
+ FROM article a
+ LEFT JOIN article_topic_map atm on a.id = atm.article_id
+ LEFT JOIN topic t on atm.topic_id = t.id
+ INNER JOIN user_reading_session urs ON urs.article_id = a.id
+ INNER JOIN language l on a.language_id = l.id
+ INNER JOIN user u ON urs.user_id = u.id
+ WHERE DATEDIFF(CURDATE(), urs.start_time) <= {self.DAYS_FOR_REPORT}
+ AND u.learned_language_id = a.language_id
+ GROUP BY a.language_id, atm.topic_id;"""
+ topic_reading_time_df = pd.read_sql(query, con=self.db_connection)
+ topic_reading_time_df["total_reading_time"] = topic_reading_time_df[
+ "total_reading_time"
+ ].apply(ms_to_mins)
+ topic_reading_time_df.loc[topic_reading_time_df["Topic"].isna(), "Topic"] = (
+ "Unclassified"
+ )
+ return topic_reading_time_df
+
+ def add_language_to_df(self, df, language_data):
+ df["Language"] = df.language_id.apply(
+ lambda x: language_data.loc[language_data.id == x, "name"].values[0]
+ )
+
+ def add_stats_to_feed(self, feed_df, article_df):
+ feed_count = article_df.feed_id.value_counts().reset_index()
+ feed_count["feed_id"] = feed_count["feed_id"].apply(int)
+ feed_count = feed_count.set_index("feed_id")
+ count_dictionary = feed_count.to_dict()["count"]
+ feed_df["Count"] = feed_df.id.apply(lambda x: count_dictionary.get(int(x), 0))
+ self.__add_feed_name(feed_df, feed_df, "id")
diff --git a/tools/report_generator/explore_report_notebook.ipynb b/tools/report_generator/explore_report_notebook.ipynb
new file mode 100644
index 00000000..42d1cf78
--- /dev/null
+++ b/tools/report_generator/explore_report_notebook.ipynb
@@ -0,0 +1,4192 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sqlalchemy import create_engine\n",
+ "import pandas as pd\n",
+ "import os\n",
+ "import matplotlib.pyplot as plt\n",
+ "import seaborn as sns\n",
+ "from generate_plots_report import DataExtractor\n",
+ "\n",
+ "\n",
+ "sns.set_theme()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data_extractor = DataExtractor(db_connection, DAYS_FOR_REPORT)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Getting Article Topics...\n",
+ "Getting Articles...\n",
+ "Getting feeds...\n",
+ "Getting Languages...\n",
+ "Getting bookmarks...\n"
+ ]
+ }
+ ],
+ "source": [
+ "article_topics_df = data_extractor.get_article_topics_df()\n",
+ "article_df = data_extractor.get_article_df()\n",
+ "feed_df = data_extractor.get_feed_df()\n",
+ "language_df = data_extractor.get_language_df()\n",
+ "bookmark_df = data_extractor.get_bookmark_df()\n",
+ "data_extractor.add_stats_to_feed(feed_df, article_df)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Getting user activity...\n"
+ ]
+ }
+ ],
+ "source": [
+ "user_reading_time_df = data_extractor.get_user_reading_activity(\n",
+ " language_df, feed_df\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "77"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(article_df[article_df.id.isin(user_reading_time_df.id)])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " id \n",
+ " language_id \n",
+ " feed_id \n",
+ " user_id \n",
+ " total_reading_time \n",
+ " Language \n",
+ " Feed Name \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2493085 \n",
+ " 3 \n",
+ " NaN \n",
+ " 4486 \n",
+ " 6.400000 \n",
+ " German \n",
+ " No Feed \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 2493213 \n",
+ " 2 \n",
+ " NaN \n",
+ " 4590 \n",
+ " 5.350000 \n",
+ " Danish \n",
+ " No Feed \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 2493357 \n",
+ " 3 \n",
+ " 76.0 \n",
+ " 4521 \n",
+ " 41.966667 \n",
+ " German \n",
+ " 76 Frankfurter All \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 2493606 \n",
+ " 2 \n",
+ " NaN \n",
+ " 4591 \n",
+ " 3.400000 \n",
+ " Danish \n",
+ " No Feed \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 2493621 \n",
+ " 9 \n",
+ " 87.0 \n",
+ " 528 \n",
+ " 4.183333 \n",
+ " Dutch \n",
+ " 87 NRC \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 105 \n",
+ " 2504948 \n",
+ " 2 \n",
+ " 160.0 \n",
+ " 4022 \n",
+ " 0.933333 \n",
+ " Danish \n",
+ " 160 videnskab \n",
+ " \n",
+ " \n",
+ " 106 \n",
+ " 2504939 \n",
+ " 2 \n",
+ " 145.0 \n",
+ " 4022 \n",
+ " 0.033333 \n",
+ " Danish \n",
+ " 145 Sport | DR \n",
+ " \n",
+ " \n",
+ " 107 \n",
+ " 2499157 \n",
+ " 2 \n",
+ " NaN \n",
+ " 4022 \n",
+ " 0.083333 \n",
+ " Danish \n",
+ " No Feed \n",
+ " \n",
+ " \n",
+ " 108 \n",
+ " 2505478 \n",
+ " 2 \n",
+ " 161.0 \n",
+ " 4022 \n",
+ " 0.266667 \n",
+ " Danish \n",
+ " 161 bt \n",
+ " \n",
+ " \n",
+ " 109 \n",
+ " 2506018 \n",
+ " 2 \n",
+ " 160.0 \n",
+ " 4022 \n",
+ " 0.300000 \n",
+ " Danish \n",
+ " 160 videnskab \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
110 rows × 7 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id language_id feed_id user_id total_reading_time Language \\\n",
+ "0 2493085 3 NaN 4486 6.400000 German \n",
+ "1 2493213 2 NaN 4590 5.350000 Danish \n",
+ "2 2493357 3 76.0 4521 41.966667 German \n",
+ "3 2493606 2 NaN 4591 3.400000 Danish \n",
+ "4 2493621 9 87.0 528 4.183333 Dutch \n",
+ ".. ... ... ... ... ... ... \n",
+ "105 2504948 2 160.0 4022 0.933333 Danish \n",
+ "106 2504939 2 145.0 4022 0.033333 Danish \n",
+ "107 2499157 2 NaN 4022 0.083333 Danish \n",
+ "108 2505478 2 161.0 4022 0.266667 Danish \n",
+ "109 2506018 2 160.0 4022 0.300000 Danish \n",
+ "\n",
+ " Feed Name \n",
+ "0 No Feed \n",
+ "1 No Feed \n",
+ "2 76 Frankfurter All \n",
+ "3 No Feed \n",
+ "4 87 NRC \n",
+ ".. ... \n",
+ "105 160 videnskab \n",
+ "106 145 Sport | DR \n",
+ "107 No Feed \n",
+ "108 161 bt \n",
+ "109 160 videnskab \n",
+ "\n",
+ "[110 rows x 7 columns]"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "user_reading_time_df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Language \n",
+ " count \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " English \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Dutch \n",
+ " 3 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " German \n",
+ " 17 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " French \n",
+ " 30 \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Danish \n",
+ " 59 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Language count\n",
+ "4 English 1\n",
+ "3 Dutch 3\n",
+ "2 German 17\n",
+ "1 French 30\n",
+ "0 Danish 59"
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "user_reading_time_df.Language.value_counts().reset_index().sort_values(\"count\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " id \n",
+ " title \n",
+ " authors \n",
+ " content \n",
+ " htmlContent \n",
+ " summary \n",
+ " word_count \n",
+ " published_time \n",
+ " fk_difficulty \n",
+ " feed_id \n",
+ " url_id \n",
+ " language_id \n",
+ " broken \n",
+ " uploader_id \n",
+ " video \n",
+ " deleted \n",
+ " img_url_id \n",
+ " Language \n",
+ " Feed Name \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2493023 \n",
+ " Tientallen Palestijnen gedood bij Israëlische ... \n",
+ " Redactie Trouw \n",
+ " 00:40\\n\\nHamas heeft Palestijnen zondag opgero... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " 00:40\\n\\nHamas heeft Palestijnen zondag opgero... \n",
+ " 8635 \n",
+ " 2024-05-27 01:27:31 \n",
+ " 70 \n",
+ " 85 \n",
+ " 2539618 \n",
+ " 9 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2539619.0 \n",
+ " Dutch \n",
+ " 85 Trouw - Filosof \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 2493024 \n",
+ " Geen slachtoffers gevonden na instorten parkee... \n",
+ " Marten Van De Wier \n",
+ " Nieuwegein\\n\\nZondagavond stortte een deel van... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Nieuwegein\\n\\nZondagavond stortte een deel van... \n",
+ " 448 \n",
+ " 2024-05-27 01:27:31 \n",
+ " 58 \n",
+ " 85 \n",
+ " 2539620 \n",
+ " 9 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2539621.0 \n",
+ " Dutch \n",
+ " 85 Trouw - Filosof \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 2493025 \n",
+ " Geen slachtoffers na instorten parkeergarage b... \n",
+ " \n",
+ " NOS Nieuws•vandaag, 02:59\\n\\nEr is niemand gew... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Er is niemand gewond geraakt bij het instorten... \n",
+ " 334 \n",
+ " 2024-05-27 01:27:39 \n",
+ " 56 \n",
+ " 89 \n",
+ " 2539622 \n",
+ " 9 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2539623.0 \n",
+ " Dutch \n",
+ " 89 NOS Nieuws \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 2493026 \n",
+ " Meerdere agenten gewond na ongeregeldheden na ... \n",
+ " \n",
+ " NOS Nieuws•vandaag, 00:48\\n\\nDoor ongeregeldhe... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Door ongeregeldheden rond de wedstrijd van FC ... \n",
+ " 181 \n",
+ " 2024-05-27 01:27:39 \n",
+ " 55 \n",
+ " 89 \n",
+ " 2539624 \n",
+ " 9 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2539625.0 \n",
+ " Dutch \n",
+ " 89 NOS Nieuws \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 2493027 \n",
+ " Tientallen doden in tentenkamp Rafah, Israël z... \n",
+ " \n",
+ " NOS Nieuws•gisteren, 23:34\\n\\nIn een tentenkam... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " In een tentenkamp voor ontheemden in Rafah woe... \n",
+ " 381 \n",
+ " 2024-05-27 01:27:39 \n",
+ " 66 \n",
+ " 89 \n",
+ " 2539626 \n",
+ " 9 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2539627.0 \n",
+ " Dutch \n",
+ " 89 NOS Nieuws \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 13651 \n",
+ " 2506913 \n",
+ " The UK doesn’t work for Disabled people. Neith... \n",
+ " \n",
+ " “This election is about who our country works ... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " So far, we’ve heard more about Starmer and Sun... \n",
+ " 809 \n",
+ " 2024-06-24 07:56:40 \n",
+ " 45 \n",
+ " 122 \n",
+ " 2566348 \n",
+ " 5 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2566349.0 \n",
+ " English \n",
+ " 122 openDemocracy \n",
+ " \n",
+ " \n",
+ " 13652 \n",
+ " 2506914 \n",
+ " How to Vet Information Before Making a Decision \n",
+ " \n",
+ " Four questions to ask when you’re considering ... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Four questions to ask when you’re considering ... \n",
+ " 311 \n",
+ " 2024-06-24 07:56:43 \n",
+ " 43 \n",
+ " 126 \n",
+ " 2566350 \n",
+ " 5 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2566351.0 \n",
+ " English \n",
+ " 126 HBR.org \n",
+ " \n",
+ " \n",
+ " 13653 \n",
+ " 2506915 \n",
+ " When It Comes to Long-Term Value, Incumbents S... \n",
+ " \n",
+ " Six steps to kickstart your company’s “digital... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Six steps to kickstart your company’s “digital... \n",
+ " 471 \n",
+ " 2024-06-24 07:56:43 \n",
+ " 53 \n",
+ " 126 \n",
+ " 2566352 \n",
+ " 5 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2566353.0 \n",
+ " English \n",
+ " 126 HBR.org \n",
+ " \n",
+ " \n",
+ " 13654 \n",
+ " 2506916 \n",
+ " Research: Warehouse and Logistics Automation W... \n",
+ " \n",
+ " A recent study suggests that blending human la... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " A recent study suggests that blending human la... \n",
+ " 205 \n",
+ " 2024-06-24 07:56:43 \n",
+ " 60 \n",
+ " 126 \n",
+ " 2566354 \n",
+ " 5 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2566355.0 \n",
+ " English \n",
+ " 126 HBR.org \n",
+ " \n",
+ " \n",
+ " 13655 \n",
+ " 2506917 \n",
+ " How Micro-Choices and Games Motivate Gig Workers \n",
+ " \n",
+ " Mike Coppola/Getty Images \\n\\nAs gig work grow... \n",
+ " <div class=\"page\" id=\"readability-page-1\"><div... \n",
+ " Ride-hail platforms claim that drivers are lar... \n",
+ " 242 \n",
+ " 2024-06-24 07:56:43 \n",
+ " 44 \n",
+ " 126 \n",
+ " 2566356 \n",
+ " 5 \n",
+ " 0 \n",
+ " None \n",
+ " 0 \n",
+ " 0 \n",
+ " 2566357.0 \n",
+ " English \n",
+ " 126 HBR.org \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
13656 rows × 19 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id title \\\n",
+ "0 2493023 Tientallen Palestijnen gedood bij Israëlische ... \n",
+ "1 2493024 Geen slachtoffers gevonden na instorten parkee... \n",
+ "2 2493025 Geen slachtoffers na instorten parkeergarage b... \n",
+ "3 2493026 Meerdere agenten gewond na ongeregeldheden na ... \n",
+ "4 2493027 Tientallen doden in tentenkamp Rafah, Israël z... \n",
+ "... ... ... \n",
+ "13651 2506913 The UK doesn’t work for Disabled people. Neith... \n",
+ "13652 2506914 How to Vet Information Before Making a Decision \n",
+ "13653 2506915 When It Comes to Long-Term Value, Incumbents S... \n",
+ "13654 2506916 Research: Warehouse and Logistics Automation W... \n",
+ "13655 2506917 How Micro-Choices and Games Motivate Gig Workers \n",
+ "\n",
+ " authors content \\\n",
+ "0 Redactie Trouw 00:40\\n\\nHamas heeft Palestijnen zondag opgero... \n",
+ "1 Marten Van De Wier Nieuwegein\\n\\nZondagavond stortte een deel van... \n",
+ "2 NOS Nieuws•vandaag, 02:59\\n\\nEr is niemand gew... \n",
+ "3 NOS Nieuws•vandaag, 00:48\\n\\nDoor ongeregeldhe... \n",
+ "4 NOS Nieuws•gisteren, 23:34\\n\\nIn een tentenkam... \n",
+ "... ... ... \n",
+ "13651 “This election is about who our country works ... \n",
+ "13652 Four questions to ask when you’re considering ... \n",
+ "13653 Six steps to kickstart your company’s “digital... \n",
+ "13654 A recent study suggests that blending human la... \n",
+ "13655 Mike Coppola/Getty Images \\n\\nAs gig work grow... \n",
+ "\n",
+ " htmlContent \\\n",
+ "0 \n",
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ " \n",
+ " Language \n",
+ " Feed Name \n",
+ " id \n",
+ " title \n",
+ " count \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Danish \n",
+ " 160 videnskab \n",
+ " 2494006 \n",
+ " Kunstig intelligens undersøger effekten af mis... \n",
+ " 3 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " French \n",
+ " 60 Le Figaro - Act \n",
+ " 2496904 \n",
+ " Albanie : à l’assaut des Alpes dinariques, par... \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " French \n",
+ " 80 L'Equipe \n",
+ " 2499838 \n",
+ " Le Trophée des champions 2025 en Afrique \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " French \n",
+ " 159 Le HuffPost : a \n",
+ " 2499467 \n",
+ " Lors de France-Luxembourg, cette drôle d’illus... \n",
+ " 2 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " Danish \n",
+ " 136 Politiken.dk - \n",
+ " 2493588 \n",
+ " Sjælden fugl får unger i Danmark for første ga... \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ "
\n",
+ " "
+ ],
+ "text/plain": [
+ " Language Feed Name id \\\n",
+ "0 Danish 160 videnskab 2494006 \n",
+ "1 French 60 Le Figaro - Act 2496904 \n",
+ "2 French 80 L'Equipe 2499838 \n",
+ "3 French 159 Le HuffPost : a 2499467 \n",
+ "4 Danish 136 Politiken.dk - 2493588 \n",
+ "\n",
+ " title count \n",
+ "0 Kunstig intelligens undersøger effekten af mis... 3 \n",
+ "1 Albanie : à l’assaut des Alpes dinariques, par... 2 \n",
+ "2 Le Trophée des champions 2025 en Afrique 2 \n",
+ "3 Lors de France-Luxembourg, cette drôle d’illus... 2 \n",
+ "4 Sjælden fugl får unger i Danmark for første ga... 1 "
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "top_5_articles_by_opened.merge(article_df[[\"id\",\"title\"]], on=\"id\")[[\"Language\", \"Feed Name\", \"id\", \"title\", \"count\"]]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from nltk.tokenize import sent_tokenize\n",
+ "from collections import Counter\n",
+ "from tqdm import tqdm\n",
+ "\n",
+ "def normalize_sent(text: str):\n",
+ " return text.lower().strip()\n",
+ "\n",
+ "def sent_count(text: str):\n",
+ " return Counter([normalize_sent(sent) for paragraph in text.split(\"\\n\\n\") for sent in sent_tokenize(paragraph) if len(sent.strip()) > 10 ])\n",
+ "\n",
+ "def get_total_sent_counts(text_list: list[str]):\n",
+ " total_counts = Counter()\n",
+ " for text in tqdm(text_list, total=len(text_list)):\n",
+ " total_counts += sent_count(text)\n",
+ " return total_counts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 1135/1135 [00:02<00:00, 461.98it/s]\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_sent_count = get_total_sent_counts(last_week_articles.content)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Counter({'18 jun.video': 34,\n",
+ " '17 jun.video': 22,\n",
+ " 'saltar recomendamos y continuar leyendo': 19,\n",
+ " 'recomendamos': 19,\n",
+ " 'final de recomendamos': 19,\n",
+ " 'blijf op de hoogte': 18,\n",
+ " 'haz clic aquí para leer más historias de bbc news mundo.': 18,\n",
+ " 'y recuerda que puedes recibir notificaciones en nuestra app.': 18,\n",
+ " 'descarga la última versión y actívalas.': 17,\n",
+ " '18 jun.binnenland': 16,\n",
+ " 'ongeldig e-mailadres.': 14,\n",
+ " 'vul nogmaals in aub.': 14,\n",
+ " 'lees\\xa0hier\\xa0ons privacybeleid.': 14,\n",
+ " 'bekijk meer van': 14,\n",
+ " 'wil je op de hoogte blijven over alles rondom oorlog in oekraïne,\\n schrijf je dan in voor onze blijf op de hoogte nieuwsbrief.': 13,\n",
+ " 'veilig betalen': 13,\n",
+ " '14 dagen bedenktijd': 13,\n",
+ " '€ 79.99€ 189.95': 13,\n",
+ " '€ 139.99€ 229.95': 13,\n",
+ " '€ 54.99€ 99.99': 13,\n",
+ " '€ 24.99€ 79.95': 13,\n",
+ " 'meer van de telegraaf webshop': 13,\n",
+ " 'lyt hos apple podcast, spotify eller ved at klikke play herunder.': 13,\n",
+ " 'sabrina günther': 12,\n",
+ " 'internationalt\\n \\n 19. jun.': 11,\n",
+ " 'menuga naar het menuga naar de inhoud': 10,\n",
+ " 'sönke sievers': 10,\n",
+ " 'kokken hannah grant giver sig sine bedste sparetip til madbudgettet og sit bedste tip til prepping-mad i den seneste udgave af podcasten spar kassen.': 10,\n",
+ " 'premiumhet beste van de telegraaf': 9,\n",
+ " 'avis des utilisateurs': 9,\n",
+ " 'artiklen er føjet til din læseliste\\n du har ulæste artikler på din læseliste': 9,\n",
+ " '19 junio 2024': 9,\n",
+ " 'annals of celebrity': 8,\n",
+ " 'design et ergonomie': 8,\n",
+ " 'artiklen er oprindelig udgivet af euroinvestor.': 8,\n",
+ " 'caractéristiques techniques': 7,\n",
+ " \"comparaison avec d'autres modèles\": 7,\n",
+ " 'de krantvideopodcastpuzzels\\xa016\\xa0°c\\xa08\\xa0kmklantenservice': 6,\n",
+ " 'nieuwsbinnenland': 6,\n",
+ " 'premium05:40binnenland': 6,\n",
+ " 'performances audio': 6,\n",
+ " 'points forts\\xa0:': 5,\n",
+ " 'pour quel type de peau ?': 5,\n",
+ " 'les commentaires ont été désactivés.': 5,\n",
+ " '18 junio 2024': 5,\n",
+ " 'our flagship newsletter highlights the best of the new yorker, including top stories, fiction, humor, and podcasts.': 4,\n",
+ " 'e-mail address': 4,\n",
+ " 'by signing up, you agree to our user agreement and privacy policy & cookie statement.': 4,\n",
+ " 'this site is protected by recaptcha and the google privacy policy and terms of service apply.': 4,\n",
+ " 'the strange journey of john lennon’s stolen patek philippe watch': 4,\n",
+ " 'for decades, yoko ono thought that the birthday gift was in her dakota apartment.': 4,\n",
+ " 'but it had been removed and sold—and now awaits a court ruling in geneva.': 4,\n",
+ " 'by jay fielden': 4,\n",
+ " 'letter from ecuador': 4,\n",
+ " 'ecuador’s risky war on narcos': 4,\n",
+ " 'does president daniel noboa’s campaign against drug gangs imperil the democracy he claims to defend?': 4,\n",
+ " 'by jon lee anderson': 4,\n",
+ " 'kanye west bought an architectural treasure—then gave it a violent remix': 4,\n",
+ " 'how the hip-hop star’s beautiful, dark, twisted fantasy turned a beach house in malibu, designed by the japanese master tadao ando, into a ruin.': 4,\n",
+ " 'by ian parker': 4,\n",
+ " 'u.s. journal': 4,\n",
+ " 'ghosts on the water': 4,\n",
+ " 'glass eels are mysterious creatures—and worth a fortune to those who catch them.': 4,\n",
+ " 'by paige williams': 4,\n",
+ " 'offer ends 2nd of july 2024.': 4,\n",
+ " '6 hours ago': 4,\n",
+ " '4 hours ago': 4,\n",
+ " 'privé nieuwsbrief': 4,\n",
+ " 'dagelijks het laatste nieuws over de sterren en royals.': 4,\n",
+ " 'premium00:02sterren': 4,\n",
+ " 'ik betwijfel het ten zeerste.': 4,\n",
+ " 'de krantvideopodcastpuzzels\\xa017\\xa0°c\\xa018\\xa0kmklantenservice': 4,\n",
+ " 'wil je op de hoogte blijven over alles rondom oorlog israël,\\n schrijf je dan in voor onze blijf op de hoogte nieuwsbrief.': 4,\n",
+ " \"qualité de l'image\": 4,\n",
+ " 'fonctionnalités smart tv': 4,\n",
+ " 'contenu conçu et proposé par digital content expert pour le figaro services.': 4,\n",
+ " 'internationalt\\n \\n 20. jun.': 4,\n",
+ " 'les avantages\\xa0:': 4,\n",
+ " 'les inconvénients\\xa0:': 4,\n",
+ " 'skuespilleren lisbet dahl er sygemeldt og må holde pause fra årets tivolirevy.': 4,\n",
+ " 'tivolirevyen spiller igen torsdag aften og til og med 14. juli.': 4,\n",
+ " 'internationalt\\n \\n \\n 19. jun.': 3,\n",
+ " 'championnats de france': 3,\n",
+ " \"autissier/l'équipe)\": 3,\n",
+ " 'ähnlich äußerte sich die sprecherin des weißen hauses, karine jean-pierre.': 3,\n",
+ " 'find anything you save across the site in your account': 3,\n",
+ " 'daily cartoon': 3,\n",
+ " 'june 18, 2024': 3,\n",
+ " 'buy new yorker cartoons »': 3,\n",
+ " 'how to motivate me during an exercise class.': 3,\n",
+ " 'why you, my roommate, should adopt a dog.': 3,\n",
+ " 'to all the women in bathroom lines we’ve befriended before.': 3,\n",
+ " 'reasons i was crying on the subway.': 3,\n",
+ " 'cult-activities coördinator seeks a new gig.': 3,\n",
+ " 'publishing a book, by the numbers.': 3,\n",
+ " 'enter the cartoon caption contest for a chance to appear in the magazine.': 3,\n",
+ " 'follow @newyorkercartoons on instagram and subscribe to the new yorker for more funny stuff.': 3,\n",
+ " 'subscribe today.': 3,\n",
+ " '3 hours ago': 3,\n",
+ " '9 hours ago': 3,\n",
+ " 'bbc indepth is the new home on the website and app for the best analysis and expertise from our top journalists.': 3,\n",
+ " 'under a distinctive new brand, we’ll bring you fresh perspectives that challenge assumptions, and deep reporting on the biggest issues to help you make sense of a complex world.': 3,\n",
+ " 'and we’ll be showcasing thought-provoking content from across bbc sounds and iplayer too.': 3,\n",
+ " 'we’re starting small but thinking big, and we want to know what you think - you can send us your feedback by clicking on the button below.': 3,\n",
+ " '5 hours ago': 3,\n",
+ " '16 hours ago': 3,\n",
+ " '10 hours ago': 3,\n",
+ " '05:40sterren': 3,\n",
+ " '18 jun.sterren': 3,\n",
+ " 'nieuwsbuitenland': 3,\n",
+ " '1 uur geledenin buitenland': 3,\n",
+ " '17 jun.buitenland': 3,\n",
+ " '05:32buitenland': 3,\n",
+ " '10:33buitenland': 3,\n",
+ " '07:00buitenland': 3,\n",
+ " '05:37buitenland': 3,\n",
+ " 'foto familie tantesh': 3,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von facebook, der den artikel ergänzt und von der redaktion empfohlen wird.': 3,\n",
+ " '-800 euros sur la philips 55oled808': 3,\n",
+ " 'promo sur le intex purespa': 3,\n",
+ " 'la tv qled tcl à moitié prix\\xa0!': 3,\n",
+ " '-1000 euros sur la samsung tq55s95c': 3,\n",
+ " 'promo sur le marantz cinema 60 dab': 3,\n",
+ " 'david lindenfeld': 3,\n",
+ " 'dans la zone': 3,\n",
+ " 'fc midtjylland møder enten ballkani fra kosovo eller santa coloma fra andorra i champions league-kvalifikationens anden runde.': 3,\n",
+ " 'det blev afgjort ved en lodtrækning i uefas hovedkvarter nyon onsdag ved middagstid.': 3,\n",
+ " 'de to mulige modstandere dyster 9.-10. juli og 16.-17. juli, og den samlede vinder gå videre til et dobbeltopgør mod den danske mester, som er seedet i anden runde.': 3,\n",
+ " 'opgørene i anden runde står til at blive afviklet 23.-24. juli og 30.-31. juli, og fc midtjylland starter ude og slutter af hjemme i herning.': 3,\n",
+ " 'ballkani må betegnes som klar favorit til at skulle en tur til det midtjyske.': 3,\n",
+ " 'santa coloma har således tabt samtlige sine hidtidige 16 opgør i de europæiske turneringer.': 3,\n",
+ " 'ballkani har klaret sig bedre, men har i to forsøg endnu ikke klaret sig videre fra champions league-kvalifikationens første runde.': 3,\n",
+ " 'til gengæld er holdet gået videre til conference league-gruppespil i de to seneste sæsoner.': 3,\n",
+ " 'her er det blevet til sejre over tyrkiske sivasspor og kroatiske dinamo zagreb samt uafgjort mod astana og cluj, men også en stribe nederlag og eliminering inden knockoutfasen.': 3,\n",
+ " 'vinder fcm dobbeltopgøret i anden runde, venter yderligere to runder, inden midtjyderne i så fald sikrer sig avancement til det meget lukrative gruppespil i champions league.': 3,\n",
+ " 'taber fcm i champions league-kvalifikations anden eller tredje runde, får holdet en ny chance i europa league-kvalifikationen, ligesom der også venter en tredje chance i conference league, hvis det også her kikser.': 3,\n",
+ " 'silkeborg deltog i lodtrækningen som useedet, hvorfor listen af mulige modstandere var af en vis kaliber.': 3,\n",
+ " 'også ajax, trabzonspor, cercle brugge og rapid wien var muligheder.': 3,\n",
+ " 'bag orkestret står james price.': 3,\n",
+ " '/ritzau/reuters': 3,\n",
+ " 'hoe kan dat?': 3,\n",
+ " 'nation’s white liberals announce they have successfully completed listening': 3,\n",
+ " '17 hours ago': 3,\n",
+ " 'promo sur la jbl xtreme 3': 3,\n",
+ " '-50% sur les focal aria 936 k2': 3,\n",
+ " '-600 euros sur la cabasse mc40 java': 3,\n",
+ " 'promo sur le dreame l10s pro ultra heat': 3,\n",
+ " 'promotion sur le ninja woodfire pro xl': 3,\n",
+ " '-2000 euros sur panasonic tx-65mz2000e': 3,\n",
+ " 'championnat de france': 3,\n",
+ " 'también puedes seguirnos en youtube, instagram, tiktok, x, facebook y en nuestro nuevo canal de whatsapp, donde encontrarás noticias de última hora y nuestro mejor contenido.': 3,\n",
+ " 'det meddeler tivoli torsdag til ritzau i en skriftlig kommentar.': 3,\n",
+ " 'det er ikke oplyst, hvad skuespilleren fejler, eller hvornår hun vender tilbage.': 3,\n",
+ " 'søndag blev to forestillinger ifølge tv 2 kosmopol aflyst grundet sygdom, men det blev ikke oplyst, hvem der var syg.': 3,\n",
+ " 'onsdagens forestilling blev ifølge mediet ligeledes aflyst.': 3,\n",
+ " 'skuespilleren afløses midlertidigt af komikeren lone rødbroe.': 3,\n",
+ " 'fra 1985 til 2022 var hun instruktør og kunstnerisk leder i cirkusrevyen.': 3,\n",
+ " 'kort før premieren på sin sidste sæson af cirkusrevyen i maj 2022 blev dahl ligeledes ramt af sygdom og måtte sygemeldes.': 3,\n",
+ " 'det skyldes dengang følgerne efter coronavirus, oplyste cirkusrevyen i en pressemeddelelse.': 3,\n",
+ " 'ud over dahls afløser består tivolirevyen af thomas eje, rikke buch bendtsen, rikke bilde, mikkel becker hilgart og james price.': 3,\n",
+ " 'det var ikke nok at inddrage': 3,\n",
+ " 'da slåskampen brød': 3,\n",
+ " 'ud, stod det klart, at man ikke': 3,\n",
+ " 'kan stoppe de britiske hooligans': 3,\n",
+ " 'jonas vingegaard udtaget': 3,\n",
+ " 'til tour de france': 3,\n",
+ " 'russisk krigsmaskine': 3,\n",
+ " 'internettet glemmer aldrig.': 3,\n",
+ " 'det ville jeg ønske, jeg havde forstået som 13-årig': 3,\n",
+ " 'kæmpe overraskelse: stor': 3,\n",
+ " 'centralbank sætter renten': 3,\n",
+ " 'ned for anden gang': 3,\n",
+ " 'lars løkke hæver stemmen:': 3,\n",
+ " '»jeg bliver så træt af det her«': 3,\n",
+ " 'formanden for': 3,\n",
+ " 'den tiltalte i korsør-sagen er ikke sindssyg – det er meget, meget værre': 3,\n",
+ " 'nogle trives alene, andre gør ikke.': 3,\n",
+ " 'folketingsmedlemmer: husk': 3,\n",
+ " 'din præst, når du har ondt i livet': 3,\n",
+ " 'denne serie er som et spark i maven - men du skal se den alligevel': 3,\n",
+ " 'onsdag aften blev stor politisk': 3,\n",
+ " 'alliance efterladt på perronen:': 3,\n",
+ " '»lidt for klogt af regeringen«': 3,\n",
+ " 'vi halter efter nabolande:': 3,\n",
+ " '»udefra ser det ud som en': 3,\n",
+ " 'tragedie i slowmotion«': 3,\n",
+ " 'medie: advokat fra tv-dokumentar lagt i økonomisk benlås af retten': 3,\n",
+ " 'sjælden harry potter-førsteudgave solgt på auktion': 3,\n",
+ " 'han var med til at forhandle den': 3,\n",
+ " 'første fred med putin.': 3,\n",
+ " 'han os om at huske bare én ting': 3,\n",
+ " 'profileret finansmand': 3,\n",
+ " 'hizbollah: »intet område« i': 3,\n",
+ " 'israel bliver »skånet for vores': 3,\n",
+ " 'raketter«, hvis der kommer krig': 3,\n",
+ " 'fejl på elnettet slukker': 3,\n",
+ " 'strømmen i hele ecuador': 3,\n",
+ " 'kun et land kan stoppe dem': 3,\n",
+ " 'læs også:\\xa0her kan kunstig intelligens påvirke flest job, mener amerikansk storbank': 3,\n",
+ " 'udvidelsen af havnen har været mange år undervejs, men blev i slutningen af maj stoppet af planklagenævnet.': 2,\n",
+ " 'den afgørelse er endelig og kan ikke indbringes for en anden administrativ myndighed.': 2,\n",
+ " 'efterfølgende lød det fra forligspartierne i aarhus byråd, at en ekstern undersøgelse skulle afdække, hvad der var gået galt i kommunens arbejde med udvidelsen.': 2,\n",
+ " 'her lød det, at kommunen stadig havde planer om en udvidelse af havnen, og derfor skulle lokalplanen genbesøges.': 2,\n",
+ " 'i perioden 2021 til 2023 har arbejdstilsynet 57 gange uddelt påbud til 46 grundskoler om at gribe ind over for et arbejdsmiljø med blandt andet vold og chikane mod lærere og pædagoger.': 2,\n",
+ " 'når arbejdstilsynet udsteder et påbud, betyder det, at der er sket en overtrædelse af arbejdsmiljøloven, og at arbejdsgiveren skal finde en løsning på problemet.': 2,\n",
+ " 'ifølge undervisningsministeriet var der i 2022 1066 folkeskoler i danmark.': 2,\n",
+ " 'i 55 ud af de 57 påbud fandt arbejdstilsynet, at der var problemer med fysisk vold mod personalet.': 2,\n",
+ " 'i 41 af tilfældene fandt tilsynet problemer med psykisk vold.': 2,\n",
+ " 'gennemgangen af rapporterne viser ifølge folkeskolen og gravercentret, at episoder med chikane eller fysiske overgreb finder sted ugentligt eller dagligt.': 2,\n",
+ " 'formand for danmarks lærerforening gordon ørskov madsen mener, at problemet er langt større end de 57 påbud.': 2,\n",
+ " '»det er helt givet.': 2,\n",
+ " 'det er det, vi hører, når vi spørger lærerne og børnehaveklasselederne.': 2,\n",
+ " 'det er langt fra første gang, at der rapporteres om problemer med vold mod lærere på landets folkeskoler.': 2,\n",
+ " 'i 2016 udstedte arbejdstilsynet 45 påbud for vold mod lærere.': 2,\n",
+ " 'i 2018 og 2019 viste en undersøgelse, at 45 procent af lærere og pædagoger i løbet af et år havde været udsat for fysisk vold.': 2,\n",
+ " 'der er desuden set eksempler på vold og grænseoverskridende adfærd mellem børn.': 2,\n",
+ " 'blandt de mest kendte er sagen fra borup skole på sjælland.': 2,\n",
+ " 'internationalt\\n \\n 18. jun.': 2,\n",
+ " 'pilgrimsfærden hajj finder sted hvert år i den islamiske kalenders sidste måned.': 2,\n",
+ " 'i år falder dette tidspunkt i midten af juni.': 2,\n",
+ " 'hajj er en af de fem søjler i islam og defineres ifølge islamisk ret som en religiøs pligt for alle muslimer, der har mulighed for at drage afsted til mekka.': 2,\n",
+ " 'le décret applique une disposition de la loi de financement de la sécurité sociale 2024.': 2,\n",
+ " 'les infirmières de pratique avancée (ipa) attendent le décret qui va permettre aux patients de prendre rendez-vous directement avec elles, sans ordonnance médicale.': 2,\n",
+ " 'ils attendent aussi un décret leur permettant de prescrire certains produits de santé, dont certains antalgiques et anti-inflammatoires.': 2,\n",
+ " 'publié le 19 juin 2024 à 07h42': 2,\n",
+ " 'on peut mieux faire.': 2,\n",
+ " \"(a.\\xa0martin/l'équipe)\": 2,\n",
+ " 'publié le 18 juin 2024 à 19h11': 2,\n",
+ " '1jour1actu a aimé\\xa0:': 2,\n",
+ " 'les informations de la nuit qu’il ne fallait pas manquer.': 2,\n",
+ " 'par\\n paul conge': 2,\n",
+ " 'par\\n jeanne auberger': 2,\n",
+ " 'elle est dans le collimateur du gouvernement depuis le début des émeutes, les autorités accusant ses responsables d’être les commanditaires des violences.': 2,\n",
+ " 'le barrage installé dans la rue par les militants a été déblayé.': 2,\n",
+ " 'les propos du président sur le changement de genre officiel sont indignes.': 2,\n",
+ " 'cette possibilité existe déjà dans la loi.': 2,\n",
+ " 'le président ignore la dose de souffrances que cela implique pour les personnes concernées.': 2,\n",
+ " \"d'autres pays ont compris qu'il faut laisser les gens se mettre…\": 2,\n",
+ " 'il estime que le président \"ignore la dose de souffrances que cela implique pour les personnes concernées\".': 2,\n",
+ " 'pour l’insoumis françois ruffin, emmanuel macron \"a choisi son camp, pour lui mieux vaut le national autoritaire que le front populaire\".': 2,\n",
+ " 'en marge d’un déplacement dans la marne, mardi, l’ex-premier ministre edouard philippe a déclaré porter \"un regard dubitatif sur ceux qui clament qu’ils sont prêts\" à occuper matignon \"alors qu’ils n’ont jamais rien géré\".': 2,\n",
+ " 'il a ainsi cité le président du rassemblement national, jordan bardella, promis à matignon en cas de succès de son parti.': 2,\n",
+ " '\"je sais que c’est dur, premier ministre.': 2,\n",
+ " '\"c’est difficile de gérer une commune, tous les maires vous le diront.': 2,\n",
+ " 'et c’est plus difficile de gérer l’etat\", a conclu edouard philippe.': 2,\n",
+ " 'la ministre des sports amélie oudéa-castéra s’est indignée mardi des propos de l’ancien champion olympique guy drut.': 2,\n",
+ " 'dans un entretien paru le même jour dans le monde, celui-ci s’est prononcé pour une alliance entre les républicains (lr), parti dont il est issu, et le rassemblement national (rn).': 2,\n",
+ " '\"je reste et je voterai les républicains, tendance éric ciotti, parce que j’approuve l’union des droites et l’alliance avec le rassemblement national (rn)\", a déclaré guy drut, ancien ministre des sports sous le gouvernement d’alain juppé (1995-1997).': 2,\n",
+ " 'ecoutez cet épisode et abonnez-vous à la loupe sur apple podcasts, spotify, deezer, google podcasts, podcast addict et amazon music.': 2,\n",
+ " 'si nous donnions de l’eau potable aux comores et à mayotte, nous n’entendrions définitivement plus parler de choléra autochtone là-bas.': 2,\n",
+ " '21\\xa0h\\xa002, dimanche 9\\xa0juin.': 2,\n",
+ " 'la france bascule dans un inconnu vertigineux, après l’annonce présidentielle de la dissolution de l’assemblée nationale.': 2,\n",
+ " 'selon la professeure émérite de droit public martine lombard, de nombreuses difficultés se dressent sur la route du rn avant de parvenir à privatiser le service public audiovisuel.': 2,\n",
+ " '17-06-2024 à 11:46': 2,\n",
+ " 'vous n’avez plus voté depuis dix, vingt ans ou plus mais vous avez décidé de rompre avec cette tradition pour les législatives\\xa0?': 2,\n",
+ " 'kein land der welt dürfe russlands aggression unterstützen.': 2,\n",
+ " 'berlin, berlin – wer fährt nach berlin?': 2,\n",
+ " 'juni bis zum 14.': 2,\n",
+ " 'juli ist deutschland gastgeber der fußball-europameisterschaft.': 2,\n",
+ " '24 mannschaften kämpfen um den titel, die erwartungen an das team von julian nagelsmann sind groß.': 2,\n",
+ " 'das finale findet im berliner olympiastadion statt.': 2,\n",
+ " 'hier finden sie news, reportagen, interviews und analysen.': 2,\n",
+ " 'seit mehr als zwei jahren führt russland einen angriffskrieg gegen das nachbarland ukraine.': 2,\n",
+ " 'die ukraine hat immer wieder angekündigt, die krim von der russischen besatzung zu befreien.': 2,\n",
+ " 'bei der em-übertragung war eine europa-karte vor dem tisch von moderator kerner und experte michael ballack eingeblendet worden, die alle teilnehmer-länder der europameisterschaft in deutschland zeigte.': 2,\n",
+ " 'dabei waren die länder mit ihren jeweiligen flaggen farblich hervorgehoben.': 2,\n",
+ " 'bei der ukraine war jedoch die krim nicht in den ukrainischen farben eingefärbt.': 2,\n",
+ " 'in sozialen medien machten mehrere nutzer auf den fehler aufmerksam und posteten screenshots.': 2,\n",
+ " '„heute ist ein neues grundlagendokument fertig, das die basis für unsere langfristigen beziehungen legen wird“, sagte putin laut russischen nachrichtenagenturen am mittwoch in der nordkoreanischen hauptstadt.': 2,\n",
+ " 'moskau und pjöngjang seien bei der stärkung ihrer bilateralen beziehungen „weit vorangekommen“.': 2,\n",
+ " 'sie sagte, die lieferung von waffen aus nordkorea hätte dazu beigetragen, dass russland in der lage sei, seinen brutalen krieg in der ukraine zu führen.': 2,\n",
+ " 'diese staaten unterstützten russlands kriegsaggression gegen die ukraine und heizten diese an.': 2,\n",
+ " '„das zeigt auch, dass unsere sicherheit nicht regional ist.': 2,\n",
+ " 'man sei auch besorgt darüber, dass russland technologie für die raketen- und atomprogramme dieser länder bereitstelle.': 2,\n",
+ " 'auch deshalb werde man beim nato-gipfel in washington im juli die zusammenarbeit mit partnern im indopazifik-raum weiter stärken, betonte stoltenberg.': 2,\n",
+ " '„das klappt.': 2,\n",
+ " 'genauso wie wir es erwartet haben.“ der ukrainische staatschef lobte dabei mehrere einheiten für nicht näher benannte erfolge.': 2,\n",
+ " 'westliche staaten hatten nach neuen russischen angriffen gegen das gebiet charkiw im nordosten der ukraine ihr verbot zum einsatz ihrer waffen gegen russisches staatsgebiet gelockert.': 2,\n",
+ " 'es sei den ukrainern gelungen, die russischen offensiven abzubremsen.': 2,\n",
+ " 'tatsächlich sind die geländegewinne der russischen truppen in den vergangenen wochen immer geringer geworden, was beobachter auch darauf zurückführen, dass nun westliche waffen nach längerer pause wieder bei den ukrainischen verteidigern ankommen.': 2,\n",
+ " 'carlota brandis': 2,\n",
+ " 'in der em-prognose der f.a.z.': 2,\n",
+ " 'von daniel memmert und fabian wunderlich zeigt sich in vier verschiedenen kategorien, wer die besten chancen hat.': 2,\n",
+ " 'die siegwahrscheinlichkeit basiert auf daten des wettmarkts.': 2,\n",
+ " 'daniel memmert, mathematiker, professor und geschäftsführender institutsleiter am institut für trainingswissenschaft und sportinformatik, kennt insbesondere auch die psychologischen tücken von vorhersagen und konnte in eigener forschung belegen, dass sich experten dabei regelmäßig überschätzen.': 2,\n",
+ " 'daher empfiehlt er statt auf einzelne expertenmeinungen lieber auf die prognosen von datenbasierten modellen zu vertrauen.': 2,\n",
+ " 'seine weiteren arbeitsschwerpunkte liegen in der bewegungswissenschaft (kognition und motorik), in der sportpsychologie (aufmerksamkeit und motivation) sowie in der sportinformatik (big data, ml, ki).': 2,\n",
+ " 'sein institut kooperiert mit verschiedenen fußball-bundesligavereinen, dax-unternehmen und organisiert den ersten internationalen weiterbildungs-masterstudiengang „spielanalyse“ sowie das zertifikat „sportdirektor im amateur- und nachwuchsleistungsfußball“.': 2,\n",
+ " 'fabian wunderlich, mathematiker, hat mehrere jahre im sportwetten-bereich gearbeitet und an der deutschen sporthochschule köln zum thema vorhersagemodelle im sport promoviert.': 2,\n",
+ " 'seine primäre expertise liegt in der anwendung von mathematischen und informatischen verfahren auf sportdaten und seine forschungsschwerpunkte unter anderem in den bereichen vorhersagemodelle, sportwetten, wettquoten sowie zufallseinflüsse im sportspiel.': 2,\n",
+ " 'gemeinsam haben sich beide in einem übersichtsartikel mit vorhersagemodellen im sport befasst und in einer aktuellen studie den hohen zufallseinfluss im fußball nachgewiesen, der letztendlich die vorhersagen so schwierig macht.': 2,\n",
+ " 'darüber hinaus wissen sie, wie wichtig wettquoten im vorhersagebereich sind, und haben den nutzen von wettquoten für die analyse von leistungsstärken und in der vorhersage von fußballspielen untersucht.': 2,\n",
+ " 'weitere aktuelle studien befassen sich mit der frage, inwiefern positionsdaten oder social-media-daten vorhersagemodelle für fußballspiele verbessern können.': 2,\n",
+ " 'während sich viele sportfans am mittwoch das zweite vorrundenspiel der dfb-elf gegen ungarn ansehen werden, muss alexander zverev auf den tennisplatz.': 2,\n",
+ " 'zur allgemeinen verwunderung setzten die veranstalter des turniers im westfälischen halle das achtelfinale des tennis-olympiasiegers gegen den italiener lorenzo sonego parallel zum zweiten auftritt der nationalelf an.': 2,\n",
+ " '„das war definitiv nicht mein wunsch“, sagte zverev am dienstagabend nach seinem erstrunden-sieg gegen oscar otte.': 2,\n",
+ " '„aber ich bestimme es nicht.': 2,\n",
+ " 'wenn ich es bestimmen würde, würde ich es anders machen.': 2,\n",
+ " 'ich glaube, es war um ehrlich zu sein nicht schlau vom turnier“, sagte der weltranglistenvierte, der selbst großer fußball-fan ist.': 2,\n",
+ " '„wenn ich nicht spielen würde, würde ich mir auch kein tennis-match anschauen, sondern würde fußball gucken.“': 2,\n",
+ " 'die veranstalter wollten sich zunächst nicht zu dem ungewöhnlichen spielplan äußern.': 2,\n",
+ " 'das zverev-match ist die vierte begegnung des tages in der owl arena.': 2,\n",
+ " 'zuvor spielen unter anderem jan-lennard struff, dominik koepfer und der russe daniil medwedew.': 2,\n",
+ " 'erst danach ist zverev an der reihe.': 2,\n",
+ " 'kurios: die organisatoren werben damit, dass von 18.00 uhr an hinter der arena ein public viewing zu deutschland gegen ungarn stattfinden sol.': 2,\n",
+ " 'genau zu dem zeitpunkt, wenn in zverev das zugpferd der veranstaltung im einsatz ist.': 2,\n",
+ " 'by adam douglas thompson': 2,\n",
+ " '8 hours ago': 2,\n",
+ " '“i flew from england to washington dc to hear in person what the boeing ceo has to say to the senate and to the world about any safety improvements made at that corporation,” said zipporah kuria, whose father was killed in the 2019 crash of a boeing 737 max 8 jet.': 2,\n",
+ " '“i also continue to press the us government to hold boeing and its corporate executives criminally responsible for the deaths of 346 people.': 2,\n",
+ " 'we will not rest until we see justice.”': 2,\n",
+ " 'by\\xa0alex mcintyre,\\xa0bbc news, west midlands': 2,\n",
+ " '2 hours ago': 2,\n",
+ " \"if you would like to hear more about election issues in wales and get the chance to have your say you can sign up to the bbc's live audience programmes here.\": 2,\n",
+ " '13 hours ago': 2,\n",
+ " 'at the economist we are best known for producing a weekly newspaper, but we also publish an annual every november, looking forward to the year ahead.': 2,\n",
+ " 'the latest edition, “the world in 2020” has just appeared.': 2,\n",
+ " 'it features analysis and forecasts from our journalists (unusually, this is one occasion on which we get bylines), our colleagues at the economist intelligence unit (who provide pithy summaries of the outlook for dozens of countries and industries) and a distinguished group of external contributors.': 2,\n",
+ " 'this year this final group included demis hassabis, co-founder of deepmind; jacinda ardern, prime minister of new zealand; ren zhengfei, founder of huawei; and robert f. smith, a private-equity billionaire who, while giving a commencement address in may at morehouse college, told the class of 2019 that he would pay off their student loans when they graduate.': 2,\n",
+ " 'our aim with this annual, of which i am the deputy editor, is not so much to make precise predictions about the coming year as to give readers a wide range of stimulating ideas and perspectives to help them navigate it.': 2,\n",
+ " 'but all our contributors have one thing in common: they are human.': 2,\n",
+ " 'so for this year’s edition, i thought it might be fun to ask an artificial intelligence (ai) about the future.': 2,\n",
+ " 'i have been tinkering with chatbots and text-generating algorithms since i was a teenager, and i went to university to study ai in the late 1980s—only to discover, alas, that ai didn’t really work.': 2,\n",
+ " 'but in recent years a specific technique called deep learning has led to extraordinary progress in the field.': 2,\n",
+ " 'most of what is called ai today, from facial recognition to voice assistants to machine translation, is in fact deep learning if you look under the hood.': 2,\n",
+ " 'and in february 2019 openai, a research outfit based in san francisco, unveiled a “large-scale unsupervised language model” called gpt-2 that was created by applying a flavour of deep learning, called unsupervised learning, to 40 gigabytes of text extracted from 8m web pages on a wide range of topics.': 2,\n",
+ " 'the resulting system is uncannily good at generating text in a specific style: you give it a few words as a prompt, and it then guesses what comes next, based on patterns in the text it was trained on, like a sort of supercharged autocomplete, powered by gigabytes of past examples.': 2,\n",
+ " 'openai’s announcement included examples of gpt-2 writing tolkienesque fantasy fiction and (fictitious) news-agency stories about unicorns and stolen nuclear material, complete with quotes from (entirely made-up) sources.': 2,\n",
+ " 'it also turned out to be surprisingly good at comprehension, summarisation and other language tasks, despite not having been designed to do those things.': 2,\n",
+ " 'citing the risk that this program might be misused by propagandists to generate “fake news” stories, openai decided not to release the full version of gpt-2 right away; instead, it was released in stages, starting with an initial, watered-down version, and slowly working up to the full-strength version over several months.': 2,\n",
+ " 'this was something of a publicity stunt, and resulted in many headlines along the lines of “ai lab decides its creation is too dangerous to make public”.': 2,\n",
+ " 'but it was also a way for openai to emphasise the point that it takes the misuse of technology seriously (its mission is “to ensure that artificial general intelligence benefits all of humanity”), with the strong implication that others in the tech industry ought to do the same.': 2,\n",
+ " 'when i saw gpt-2’s results, though, its propaganda potential was not what most interested me.': 2,\n",
+ " 'instead i began to wonder how i could use it as a chatbot, like the ones i used to play with in the 1980s.': 2,\n",
+ " '(the most famous example from the early personal-computer era is eliza, but my favourite was racter, a text-generation system that wrote a book called “the policeman’s beard is half-constructed”.)': 2,\n",
+ " 'helpfully for me, the gpt-2 code is available on github; even more helpfully, it can be accessed via a jupyter notebook created by ignacio lópez-francos, a researcher at nasa.': 2,\n",
+ " 'this spins up a powerful computer at google, loads the gpt-2 model onto it, and then lets anyone play with it via a web browser.': 2,\n",
+ " 'with a bit of fiddling i figured how i could use it to do an “interview” with gpt-2.': 2,\n",
+ " 'i thought it would be amusing to get a deep-learning system to generate answers to questions about the impact of ai on society in the coming decades, a subject of endless speculation and debate.': 2,\n",
+ " 'human experts cannot agree on whether robots and ai will lead to mass unemployment or not, for example.': 2,\n",
+ " 'might a machine produce a more coherent answer?': 2,\n",
+ " 'probably not, but it would be an interesting experiment.': 2,\n",
+ " 'of course, gpt-2 cannot really predict the future.': 2,\n",
+ " 'for a start, it doesn’t actually understand anything: it just sometimes appears to, because it is very good at generating text in particular styles, by regurgitating words and phrases it has heard before in the same kind of context in response to a prompt.': 2,\n",
+ " 'and the reams of text it was trained on were gathered in late 2017, and are thus rather out of date.': 2,\n",
+ " 'as a predictive tool, then, gpt-2 is no better than a magic 8-ball.': 2,\n",
+ " 'but i was curious about how plausible its answers might be.': 2,\n",
+ " 'it turns out that simply feeding it questions as prompts does not produce very relevant answers; instead, it helps to give it a clearer idea of context.': 2,\n",
+ " 'so i wrote an introductory paragraph, setting the scene and indicating to gpt-2 the style, tone and subject-matter of the text i wanted it to generate.': 2,\n",
+ " 'i then added a question, prefixed with “q:”, and began the next line with “a:” to indicate that the next words should be the answer.': 2,\n",
+ " '(gpt-2’s training set includes many q&as, so it recognises the format.': 2,\n",
+ " 'similarly, it can be prompted to generate numbered lists, or recipes, which also appear in its training data.)': 2,\n",
+ " 'the first prompt i used was:': 2,\n",
+ " 'i configured gpt-2 to generate five responses to each question and set the maximum output length to 75 words.': 2,\n",
+ " '(i did all this in september, so i used the 774m version of the gpt-2 model; the full-strength version had not been released at the time, though it since has been.)': 2,\n",
+ " 'here is a typical answer:': 2,\n",
+ " 'in this case gpt-2 has provided an answer to my original question, and has then generated subsequent questions and answers.': 2,\n",
+ " 'the “gartner symposium on data-driven technologies” is an entirely made-up event, but is a surprisingly plausible invention (the gartner data analytics summit, by contrast, does really exist).': 2,\n",
+ " 'here is another response to the same question, which starts with a much less interesting answer (and also includes follow-on questions and answers generated by gpt-2):': 2,\n",
+ " 'and here’s another one:': 2,\n",
+ " 'in this case, the follow-on questions and answers show that gpt-2 is generating text in the right subject area, namely the relationship between people and machines.': 2,\n",
+ " 'but that wasn’t part of the answer to my initial question.': 2,\n",
+ " 'so to generate my “interview”, i selected the most coherent, interesting or amusing of the five responses in each case, chopping off any follow-on questions and answers at the end.': 2,\n",
+ " 'i then added the resulting answer, and my next question, to the end of the prompt, and fed it back into gpt-2.': 2,\n",
+ " 'taking the first example above, that would mean extending the prompt as follows:': 2,\n",
+ " 'repeatedly extending the prompt in this way ensured that the questions and answers took place in the same context.': 2,\n",
+ " 'in fact, there is a limit to the size of the input prompt, so after several questions i had to remove the initial paragraph from the prompt, and just feed in the preceding set of question and answer pairs.': 2,\n",
+ " 'here is the resulting article, which was published in “the world in 2020”.': 2,\n",
+ " 'it includes the following exchange about the risks of ai:': 2,\n",
+ " 'q: how worried do you think we humans should be that \\xadmachines will take our jobs?a: it depends what role machine intelligence will play.': 2,\n",
+ " 'machine intelligence in some cases will be useful for solving problems, such as translation.': 2,\n",
+ " 'but in other cases, such as in finance or medicine, it will replace people.': 2,\n",
+ " 'q: do fake news stories, generated using ai, pose a threat to democracy?': 2,\n",
+ " 'are we likely to see this tactic being used in the 2020 american presidential elections?a: yes, we’ll probably see them.': 2,\n",
+ " 'it’s just a matter of when.': 2,\n",
+ " 'fake news stories are generally generated by political campaigns, and have the potential to have a huge impact on the outcome of an election.': 2,\n",
+ " 'this is because they spread misinformation, often with no basis in fact.': 2,\n",
+ " 'some people on twitter have challenged my use of the word “unedited” to describe these answers.': 2,\n",
+ " 'they have a point.': 2,\n",
+ " 'as explained above, i selected an answer from the five responses generated in each case (and did not keep the discarded responses, a decision i now regret).': 2,\n",
+ " 'i also lopped off any follow-on questions and answers.': 2,\n",
+ " 'i did not tinker with the text of the resulting answer; each of the answers in the piece really was generated in that form by gpt-2.': 2,\n",
+ " 'but calling them “unedited” was, in hindsight, something of a stretch.': 2,\n",
+ " 'several people also asked for more detail about how i conducted the interview, given that there was not room to explain it in the original article (the length of which was limited to a single printed page).': 2,\n",
+ " 'that’s why i’ve written this post.': 2,\n",
+ " 'if you want to give gpt-2 a quick try, though, there are easier ways to do it, though they allow less control: talktotransformer.com, another web-based interface to gpt-2 (which is named after the program’s so-called transformer-based architecture), makes it as easy as using a search engine.': 2,\n",
+ " 'mine is just one contribution to a burgeoning field: the new yorker used a specially tuned version of gpt-2 to generate paragraphs in the middle of an article by john seabrook, and the new york times used it, and a similar text-generation system developed by the allen institute, to create paragraphs of “fake news”, challenging readers to distinguish between human- and computer-generated disinformation.': 2,\n",
+ " 'gpt-2 has also been used to generate recipes, fan fiction and poetry (see janelle shane’s hilarious website, aiweirdness, for some of the funniest examples).': 2,\n",
+ " 'in nearly all of these cases human selection has played a role, picking out the most interesting examples from its output.': 2,\n",
+ " 'does that give a misleading impression of what gpt-2 and similar systems are capable of?': 2,\n",
+ " 'one of the great things about this technology is that, simply by playing around with gpt-2 in a web browser, you can decide the answer to that question for yourself.': 2,\n",
+ " 'tom standage is deputy editor of the economist and of “the world in 2020”.': 2,\n",
+ " 'premium11:45binnenland': 2,\n",
+ " 'premium10:52buitenland': 2,\n",
+ " 'premium10:00buitenland': 2,\n",
+ " 'premium08:21binnenland': 2,\n",
+ " 'premium18 jun.cultuur': 2,\n",
+ " '18 jun.financieel': 2,\n",
+ " '©\\xa0getty images': 2,\n",
+ " 'premium17 jun.sterren': 2,\n",
+ " \"foto's familie tantesh\": 2,\n",
+ " '26 mei 2023': 2,\n",
+ " 'oranje heeft sinds dit ek eindelijk weer een vaste doelman.': 2,\n",
+ " 'de opvoedvraag': 2,\n",
+ " 'een 11-jarig meisje werkt aan een glorieuze toekomst als jonge internetondernemer.': 2,\n",
+ " 'maar wat als ze daardoor in financiële problemen komt?': 2,\n",
+ " 'meiden die armbandjes maken of jongens die snoep importeren uit de vs en dit aanprijzen via tiktok of instagram.': 2,\n",
+ " 'nog nooit was het als jongere zo makkelijk om een eigen bedrijfje te beginnen.': 2,\n",
+ " '“onze dochter maakt zelf armbandjes en koopt haarspelden die ze met winst doorverkoopt.': 2,\n",
+ " 'we vinden haar ondernemingszin leuk om te zien.': 2,\n",
+ " 'maar we hebben zelf weinig verstand van ondernemen en weten niet zo goed waar we op moeten letten”, zeggen haar ouders.': 2,\n",
+ " '“we zouden het vreselijk vinden als ze door haar enthousiasme in de problemen komt.”': 2,\n",
+ " '“laat haar lekker uitproberen.': 2,\n",
+ " 'ondernemen is leuk, ze kan er veel van leren en misschien verdient ze er ook nog wat geld mee”, zegt kim meijer van geldboompje en auteur van van jouw idee naar eigen baas.': 2,\n",
+ " 'hierin geeft zij jongeren tips en advies om hun beginnende ondernemersdroom waar te maken.': 2,\n",
+ " 'het meisje is met 11 jaar wat aan de jonge kant, maar dat is geen reden om haar te ontmoedigen.': 2,\n",
+ " 'er zijn zelfs kinderen van 9 of 10 jaar die al een eigen bedrijfje starten.': 2,\n",
+ " 'er zijn steeds meer minderjarige ondernemers, weet gerdine annaars, adviseur bij de kamer van koophandel en gespecialiseerd in jonge ondernemers.': 2,\n",
+ " 'op 1 januari 2018 stonden er in het kvk-handelsregister nog 792 ondernemers van twaalf tot en met zeventien jaar ingeschreven.': 2,\n",
+ " 'op 1 januari 2024 waren dat er al 3250.': 2,\n",
+ " 'en dat zijn alleen de jongeren die zich officieel hebben aangemeld.': 2,\n",
+ " '“er zijn ook kinderen en jongeren die ondernemen, maar zich niet hebben ingeschreven”, zegt annaars.': 2,\n",
+ " '“dat is namelijk niet altijd verplicht.”': 2,\n",
+ " 'qua papierwinkel hoeft er aanvankelijk niet zo veel geregeld te worden.': 2,\n",
+ " 'de kamer van koophandel geeft uitleg op de site, speciaal voor ouders.': 2,\n",
+ " 'annaars: “zolang je op kleine schaal producten of diensten aanbiedt, is het vooral een leuke bijverdienste of hobby.': 2,\n",
+ " 'pas als je meer geld investeert, een wat grotere omzet hebt, actief klanten werft en reclame maakt en veel tijd aan je bedrijf besteedt, moet je je inschrijven bij de kvk.': 2,\n",
+ " 'voor veel kinderen geldt dat niet direct.': 2,\n",
+ " 'wel kan het zo zijn dat je belasting moet betalen over je inkomsten.': 2,\n",
+ " 'het is dus altijd slim om een overzicht te hebben over je kosten, opbrengsten en uren die je eraan besteedt.': 2,\n",
+ " 'hier kunnen ouders hun kind zeker bij helpen.”': 2,\n",
+ " 'geld verdienen is leuk, maar zou niet het hoofddoel moeten zijn.': 2,\n",
+ " 'meijer: “als je sommige influencers op sociale media ziet, denk je dat je er steenrijk van wordt.': 2,\n",
+ " 'maar dat is meestal niet zo.': 2,\n",
+ " 'het is goed om dat je kind voor te houden.': 2,\n",
+ " 'en het is goed om mee te geven dat hard werken niet altijd loont.': 2,\n",
+ " 'het kan misgaan.”': 2,\n",
+ " 'wat is mijn idee, wat zijn mijn doelen, wie of wat heb ik ervoor nodig?': 2,\n",
+ " '“je hoeft geen uitgebreid bedrijfsplan te hebben, maar je moet er wel over nagedacht hebben”, aldus meijer.': 2,\n",
+ " 'zo zal het meisje wat geld moeten investeren voordat ze iets kan verkopen.': 2,\n",
+ " '“denk bijvoorbeeld aan kraaltjes of verpakkingsmateriaal.': 2,\n",
+ " 'als je armbandjes maakt, kom je met 100 euro al een eind, maar het kan ook een stuk duurder uitpakken.': 2,\n",
+ " 'die kosten moet je meenemen in de prijs van je product.”': 2,\n",
+ " 'het ‘startkapitaal’ leent het meisje misschien van haar ouders of ze gebruikt er spaargeld voor.': 2,\n",
+ " 'meijer: “op deze manier leert ze wat het betekent om een lening te hebben en deze terug te moeten betalen.”': 2,\n",
+ " 'ondernemen heeft niet alleen maar leuke kanten, zoals filmpjes online zetten.': 2,\n",
+ " 'het kost best veel tijd, terwijl een kind ook gewoon naar school moet of wil sporten.': 2,\n",
+ " '“bewaak als ouder dus de tijd die je kind eraan kwijt is”, zegt annaars.': 2,\n",
+ " 'verder is het belangrijk om in de gaten te houden of er geen misbruik van het kind wordt gemaakt.': 2,\n",
+ " 'bijvoorbeeld door een klagende klant of iemand die niet wil betalen.': 2,\n",
+ " 'meijer: “tegelijkertijd: ook daar leer je van.': 2,\n",
+ " 'hoe kan ik het een volgende keer beter doen?': 2,\n",
+ " 'zorg er vooral voor dat je kind kan genieten van wat ze leert én wat ze ermee verdient.”': 2,\n",
+ " 'is het normaal dat onze zoon (13) alles drie keer checkt?': 2,\n",
+ " '‘onze zoon slaat in een boze bui mijn vrouw’': 2,\n",
+ " 'ons kleinkind daagt ons uit met storend, destructief gedrag': 2,\n",
+ " 'de goedkeuring van de hongaarse premier orbán maakt ruttes benoeming tot navo-baas zeker.': 2,\n",
+ " 'de twee premiers stonden zelfs glimlachend en handenschuddend op de foto.': 2,\n",
+ " 'maar dat kan niet.': 2,\n",
+ " 'woorden doen ertoe.': 2,\n",
+ " 'ga naar een specifiek onderdeel:': 2,\n",
+ " 'met succes.': 2,\n",
+ " 'traangas maakt ademhalen lastig.': 2,\n",
+ " 'het brandt op de huid.': 2,\n",
+ " 'de lucht is een ziekmaker.': 2,\n",
+ " 'hoe kan die schoner worden?': 2,\n",
+ " 'ik heb geen excuses nodig, van niemand.': 2,\n",
+ " 'nos nieuws•vandaag, 12:02': 2,\n",
+ " 'china is ontstemd over een bezoek dat amerikaanse politici vandaag hebben gebracht aan de dalai lama.': 2,\n",
+ " 'volgens peking geeft een audiëntie bij de leider van de tibetaanse boeddhisten \"de wereld het verkeerde signaal\".': 2,\n",
+ " 'een delegatie van zowel republikeinse als democratische congresleden zocht de 88-jarige spiritueel leider vandaag op in zijn hoofdkwartier in het indiase dharamshala, waar hij sinds 1959 woont nadat china tibet had geannexeerd.': 2,\n",
+ " 'het bezoek werd geleid door de republikeinse voorzitter van de buitenlandcommissie van het huis van afgevaardigden, michael mccaul.': 2,\n",
+ " 'ook de democratische oud-voorzitter van het huis nancy pelosi reisde mee.': 2,\n",
+ " 'de ontmoeting komt op een moment dat de vs en china meer toenadering zoeken na jaren van onderlinge wrevel over de economische betrekkingen, mensenrechten en de internationale verhoudingen.': 2,\n",
+ " \"tegelijkertijd zijn de twee grootmachten het nog altijd oneens over grote dossiers, zoals china's rugdekking van poetin, de status van taiwan en chinese expansie ten koste van andere landen in de regio.\": 2,\n",
+ " 'china had de delegatie vooraf gewaarschuwd weg te blijven.': 2,\n",
+ " '\"deze week nog kregen we een brief van de chinese communistische partij met een waarschuwing niet hier te komen\", vertelde mccaul het publiek na het bezoek.': 2,\n",
+ " '\"maar we laten ons niet intimideren, want hier zijn we.\"': 2,\n",
+ " 'de opmerking werd met gejuich ontvangen.': 2,\n",
+ " 'het bezoek stond in het teken van een oproep van het amerikaanse congres aan china om de dialoog met de dalai lama te hervatten.': 2,\n",
+ " 'het land heeft nooit de tibetaanse regering in ballingschap erkend en er is sinds 2010 geen onderling contact meer.': 2,\n",
+ " 'china ziet die oproepen als bemoeienis met de binnenlandse politiek.': 2,\n",
+ " 'het wijst erop dat tibet eeuwenlang onderdeel was van china en zegt dat de annexatie rust en vooruitgang heeft gebracht.': 2,\n",
+ " '\"iedereen weet dat de veertiende dalai lama niet alleen een religieus figuur is, maar als politiek banneling onder het mom van religie anti-chinese separatistische activiteiten ontplooit\", stelt een chinese regeringswoordvoerder, die de vs opriep al het contact met de tibetaanse leider te verbreken.': 2,\n",
+ " 'de dalai lama zelf ontkent uit te zijn op tibetaanse onafhankelijkheid en zegt alleen te pleiten voor meer autonomie en bescherming van geloofsgenoten.': 2,\n",
+ " 'china ligt al jaren onder vuur voor het onderdrukken van de tibetanen; critici wijzen erop dat de vrijheid van meningsuiting beperkt is en dat tibetanen hun cultuur en geloof niet vrijuit kunnen uiten.': 2,\n",
+ " 'het land is al jaren zo goed als ontoegankelijk voor buitenstaanders.': 2,\n",
+ " 'china waarschuwt het witte huis de congresverklaring niet officieel te bekrachtigen, omdat er dan \"krachtdadige maatregelen\" zullen volgen.': 2,\n",
+ " 'de woordvoerder ging niet in op wat dat precies zou betekenen.': 2,\n",
+ " 'in het verleden heeft china vaker geprikkeld gereageerd op amerikaanse delegaties in de regio.': 2,\n",
+ " 'zo leidde een bezoek van pelosi aan taiwan tot uitgebreide chinese militaire oefeningen rond het eiland.': 2,\n",
+ " 'een nieuw precair moment volgt mogelijk later deze week, als de dalai lama naar de vs reist voor een kniebehandeling.': 2,\n",
+ " 'het is nog niet bekend of hij dan verdere ontmoetingen zal hebben met amerikaanse afgevaardigden.': 2,\n",
+ " 'in het verleden had de dalai lama ontmoetingen met alle amerikaanse presidenten, op donald trump na.': 2,\n",
+ " 'ook president biden heeft hij tot nu toe nog niet ontmoet.': 2,\n",
+ " 'nos nieuws•vandaag, 09:25': 2,\n",
+ " 'de fnp-fractie in de provincie wil instemmen met bezuinigingen van in totaal 800.000 euro, terwijl de tien fnp-wethouders van gemeenten in friesland fel tegen zijn.': 2,\n",
+ " '\"fries taalbeleid en cultuur de nek laten omdraaien door de fnp kan niet\", schrijft wethouder jan dijkstra (fnp) van de gemeente waadhoeke in een brief aan de statenfractie die is ingezien door omrop fryslân.': 2,\n",
+ " 'de bezuinigingen zitten al een tijdje in de pen en leidden begin juni nog tot een protestmanifestatie van cultuurorganisaties.': 2,\n",
+ " '\"ik vind de bezuinigingen niet nodig en onacceptabel\", zei directeur douwe zeldenrust van keunstwurk toen.': 2,\n",
+ " 'keunstwurk houdt zich bezig met talentontwikkeling bij jongeren, amateurkunst en cultuureducatie.': 2,\n",
+ " '\"zo maak je een boel dingen kapot die je juist nodig hebt na corona\", aldus zeldenrust.': 2,\n",
+ " 'ook de vereniging van friese gemeenten (vfg) heeft zorgen over de voorgestelde bezuinigingen.': 2,\n",
+ " 'maar de fnp in de provincie is toch van plan om in te stemmen.': 2,\n",
+ " '\"het is nu feitelijk voor het eerst dat de provincie fryslân echt moet bezuinigen.': 2,\n",
+ " 'dat is ook verantwoordelijkheid nemen en besturen.': 2,\n",
+ " 'besturen is niet altijd eenvoudig\", laat de fnp-statenfractie weten.': 2,\n",
+ " '\"als wij tegen de bezuinigingen stemmen, dan breken we met ons akkoord met bbb, cda en christenunie en zijn wij niet consequent.': 2,\n",
+ " 'we moeten nu de pijn nemen, ook omdat we denken dat de keuzes acceptabel zijn.\"': 2,\n",
+ " 'de fnp-statenfractie wijst er ook op dat de provincie weliswaar wil bezuinigen op taal en cultuur, maar dat het rijk juist extra geld beschikbaar stelt voor friese projecten in het kader van de nieuwe bestjoersôfspraak fryske taal en kultuer (bftk), in totaal 18 miljoen euro.': 2,\n",
+ " 'maar met dat geld uit den haag zijn organisaties als keunstwurk nog niet gered, zeggen de tien kritische wethouders.': 2,\n",
+ " '\"met eenmalig geld kun je geen structurele zaken overeind houden\", stelt wethouder dijkstra.': 2,\n",
+ " '\"juist de ondersteuning van de provincie geeft gemeenten de kans om iets met het taalbeleid te doen.': 2,\n",
+ " 'ook gemeenten die er minder mee hebben.\"': 2,\n",
+ " 'dus roept dijkstra mede namens de andere negen fnp-wethouders de statenfractie op om tegen de bezuinigingen te stemmen.': 2,\n",
+ " 'de wethouders: \"naast dat het een slechte ontwikkeling is, hebben wij hier als partij veel last van.': 2,\n",
+ " 'ik denk dat er wel andere oplossingen zijn.': 2,\n",
+ " 'daar denken we ook graag over mee.\"': 2,\n",
+ " 'provinciale staten praten vandaag over de zogeheten taalnota fries.': 2,\n",
+ " 'onderdeel van die nota zijn de voorgenomen bezuinigingen.': 2,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von youtube, der den artikel ergänzt und von der redaktion empfohlen wird.': 2,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von x.com, der den artikel ergänzt und von der redaktion empfohlen wird.': 2,\n",
+ " 'alexander bakker': 2,\n",
+ " 'lunch update': 2,\n",
+ " 'dagelijks tijdens de lunch een update van het belangrijkste nieuws.': 2,\n",
+ " 'fonctionnalités supplémentaires': 2,\n",
+ " 'die christdemokraten im europäischen parlament haben am mittwoch den csu-politiker manfred weber als vorsitzenden wiedergewählt.': 2,\n",
+ " 'weber bekam 95 prozent der stimmen, wie die fraktion der europäischen volkspartei (evp) mitteilte.': 2,\n",
+ " 'er hat das amt schon seit 2014 inne, seit 2022 ist er außerdem vorsitzender der parteienfamilie.': 2,\n",
+ " 'schon am vortag hatte die größte fraktion im neu gewählten europäischen parlament 14 abgeordnete aufgenommen, darunter sieben von der partei tisza aus ungarn.': 2,\n",
+ " 'deren vorsitzender péter magyar entschied sich entgegen früherer ankündigungen, sein mandat in straßburg anzunehmen.': 2,\n",
+ " 'er hat sich mit der europawahl als wichtigster konkurrent von regierungschef viktor orbán etabliert.': 2,\n",
+ " 'magyar begründete seinen schritt damit, dass 75 prozent der anhänger seiner neuen partei in einer online-abstimmung dafür votiert haben, dass er ins europäische parlament geht.': 2,\n",
+ " 'im ungarischen parlament wird er gleichwohl ein rederecht haben, sofern es dort um themen mit eu-bezug geht.': 2,\n",
+ " 'magyar, 43 jahre alt, war viele jahre mitglied von viktor orbáns partei fidesz, bevor er im märz der partei tisza beitrat.': 2,\n",
+ " 'als deren spitzenkandidat gewann er bei der europawahl fast 30 prozent der stimmen, während der fidesz auf 45 prozent kam.': 2,\n",
+ " 'nach der aufnahme in die evp-fraktion sagte er in brüssel, dass er zwar das recht der ukraine auf selbstverteidigung unterstütze, aber – wie orbán - weder truppen noch waffen in das land schicken werde.': 2,\n",
+ " '„ich glaube, die evp versteht die besondere, empfindliche ungarische lage in diesem krieg“, sagte er.': 2,\n",
+ " 'die weiteren abgeordneten, die von der evp neu aufgenommen wurden, kommen von der familienpartei in deutschland, von zwei neuen parteien aus den niederlanden sowie aus dänemark und der tschechischen republik.': 2,\n",
+ " 'ein abgeordneter von der kndp aus ungarn, die eng mit dem fidesz verknüpft ist, verließ aus protest gegen die aufnahme von tisza, die fraktion.': 2,\n",
+ " 'sie ist nun 189 abgeordnete groß; das sind 13 sitze mehr als im scheidenden parlament.': 2,\n",
+ " 'die zuwächse sind somit das ergebnis der von weber betriebenen expansionsstrategie und nicht von gewinnen der mitgliedsparteien.': 2,\n",
+ " 'allerdings ist es der evp bisher nicht gelungen, die flämischen nationalisten von der n-va zu sich herüberzuziehen.': 2,\n",
+ " 'die partei fühlt sich seit längerem unwohl in der nationalkonservativen fraktion der europäischen konservativen und reformer, die rechts von der evp steht.': 2,\n",
+ " 'ihr kommt nun besonderes gewicht zu, weil sie die belgische parlamentswahl gewonnen hat und mit ihrem vorsitzenden bart de wever den nächsten ministerpräsidenten stellen könnte.': 2,\n",
+ " 'allerdings ist ihr verhältnis zu den flämischen christdemokraten von der partei cd&v, die der evp angehören, derzeit so schlecht, dass sondierungen zu keiner annäherung führten.': 2,\n",
+ " 'auch die fraktion der grünen wählte am mittwoch ihren neuen fraktionsvorstand.': 2,\n",
+ " 'wie erwartet, wurden die beiden spitzenkandidaten im europawahlkampf, terry reintke aus deutschland und bas eickhout aus den niederlanden, als ko-vorsitzende gewählt.': 2,\n",
+ " 'sie bemühen sich, teil der neuen mehrheit im europäischen parlament zu werden.': 2,\n",
+ " '„wir sind der verlässliche und konstruktive partner für eine demokratische proeuropäische mehrheit“, teilte reintke nach ihrer wahl mit.': 2,\n",
+ " 'die evp führt jedoch auch gespräche mit vertretern der ekr-fraktion.': 2,\n",
+ " 'offen ist, ob die sondierungen in eine schriftliche vereinbarung münden, wie sie sich die grünen wünschen.': 2,\n",
+ " 'getragen wird die mehrheit im parlament auf jeden fall von evp, sozialdemokraten und liberalen.': 2,\n",
+ " 'sie kommen zusammen auf 405 von 720 abgeordneten.': 2,\n",
+ " 'die fraktionen von sozialdemokraten und liberalen konstituieren sich erst in der kommenden woche.': 2,\n",
+ " 'bei den liberalen deutet sich an, dass die bisherige vorsitzende valérie hayer abgelöst wird.': 2,\n",
+ " 'hayer verlor als spitzenkandidatin der liste von präsident emmanuel macron zehn sitze in frankreich.': 2,\n",
+ " 'favoritin auf ihre nachfolge ist die frühere belgische premierministerin sophie wilmès.': 2,\n",
+ " 'die wallonische liberale hatte als spitzenkandidatin ihrer partei ein sehr gutes ergebnis geholt.': 2,\n",
+ " 'mit ihr würden sich die gewichte in der fraktion wieder von linksliberalen hin zu wirtschaftsliberalen verschieben.': 2,\n",
+ " 'in keiner kunstform lässt sich die atomexplosionsartige energie von liebe auf den ersten blick so gut darstellen wie im film.': 2,\n",
+ " 'wo sonst findet man bilder für etwas, das sich in worten nur unzulänglich ausdrücken lässt?': 2,\n",
+ " '„es verschlug mir den atem“, wird kathy versuchen, ihr erstes treffen mit benny zu beschreiben.': 2,\n",
+ " 'die kamera findet dafür viel bessere ausdrucksmittel: wenn kathy in einer rauchigen bar benny entdeckt, friert die zeit ein.': 2,\n",
+ " 'die beiden sehen sich an, von einem ende des raums zum anderen, und alles um sie her stürzt ins belanglose.': 2,\n",
+ " 'die musik verebbt, die bewegungen der billardspieler um benny herum verwischen ins nichts, und das licht der schummerigen lampe über dem pooltisch fließt wie ein warmer heiligenschein um seinen körper.': 2,\n",
+ " 'schon hier sind zwei dinge klar: um diese beiden ist es von jetzt an geschehen.': 2,\n",
+ " 'und wir sehen all das mit den augen der jungen frau.': 2,\n",
+ " 'so wie die linse hier bennys durchtrainierte oberarme unter der geöffneten lederweste abtastet, schauen filme sonst auf weibliche körper.': 2,\n",
+ " '„the bikeriders“ aber erzählt von einer männerwelt aus der perspektive von kathy.': 2,\n",
+ " 'es ist ein kluger trick, den der amerikanische regisseur jeff nichols anwendet; geschichten über harte jungs auf schnellen motorrädern kennt man ja ganz anders.': 2,\n",
+ " 'der gonzo-journalist hunter s. thompson schloss sich mitte der sechzigerjahre eine weile den „hells angels“ in kalifornien an, am anderen ende des landes dokumentierte der fotograf danny lyon von 1965 bis 1973 den „outlaws motorcycle club“ in chicago.': 2,\n",
+ " 'beide lassen ehrfurcht und faszination in ihren beschreibungen und dokumentationen mitschwingen.': 2,\n",
+ " 'lyons fotoreportagen liegen „the bikeriders“ zugrunde.': 2,\n",
+ " 'statt jedoch den fotografen von den gesetzlosen schwärmen zu lassen, überlässt nichols eben einer frau das wort, die diese geschichte hautnah miterlebt hat.': 2,\n",
+ " 'sie erzählt also dem journalisten danny (mike faist), wie alles begann.': 2,\n",
+ " 'die treffen der beiden bilden den roten faden, strukturieren die geschichte.': 2,\n",
+ " 'mal im waschsalon sitzend, mal beim kaffee auf ihrer veranda berichtet sie von zwei männern, die ihr leben geprägt haben.': 2,\n",
+ " 'benny (austin butler) ist ein draufgänger, der sich von niemandem etwas vorschreiben lässt, weder vom gesetz noch von seiner freundin.': 2,\n",
+ " 'der einzige mensch, zu dem er aufschaut, ist johnny (tom hardy) – ein mechaniker, der motorräder liebt und sich autorität unter den anderen bikern verschafft hat.': 2,\n",
+ " 'wie ihm das gelang, macht der film gleich zu beginn klar.': 2,\n",
+ " 'als ein aufmüpfiger hüne johnnys entscheidungen in zweifel zieht, fordert der ihn zum zweikampf auf einer schlammigen rennstrecke.': 2,\n",
+ " 'die beiden gehen mit fäusten aufeinander los, treten und boxen, was das zeug hält.': 2,\n",
+ " '„johnny war nicht stärker als der typ, aber er war fieser“, konstatiert kathy, während man sieht, wie der anführer dem herausforderer ohne mit der wimper zu zucken einen finger bricht.': 2,\n",
+ " '„the bikeriders“ verklärt hier aber nicht etwa die schiere brutalität, sondern erforscht mit sinn für nuancen die mechanismen von macht, spürt dabei dem kinonotorischen freiheitsdrang junger amerikaner in den fünfzigerjahren nach und analysiert, wie die ereignisse großer politik auch in die kleinsten gesellschaftsstrukturen zurückspielen.': 2,\n",
+ " 'wenn junge männer aus prekären familien mit sehnsüchtigen blicken den bikern hinterherblicken und danach spontan einen autoscheinwerfer einschlagen, ist das kein platter ausdruck der verführungskunst eines motorradkults, sondern die aufstellung einer gleichung: pubertäre energie plus soziale ungleichheit schafft mythen der rebellion.': 2,\n",
+ " 'dass die selbst johnny trotz all seiner natürlichen autorität nicht mehr unter kontrolle bekommen kann, zeigt sich spätestens, wenn sich dem motorradklub jungs anschließen, die frisch aus dem vietnamkrieg zurückgekehrt sind und neben schlechten manieren auch ihre drogen und traumata mitgebracht haben.': 2,\n",
+ " 'regisseur nichols versucht hier keineswegs, „easy rider“ zu wiederholen.': 2,\n",
+ " 'er nimmt zwar ikonische bilder der motorradfahrten auf, baut sie aber mit eigener ästhetik aus.': 2,\n",
+ " 'und er verlässt sich ansonsten auf den instinkt, der ihn bereits solch einprägsame filme erschaffen ließ wie das jugenddrama „mud“ mit matthew mcconaughey oder das liebesdrama „loving“ über das paar, das die amerikanischen gesetze gegen mischehen außer kraft setzte.': 2,\n",
+ " 'nichols bedient sich dafür ambivalenter figuren und exzellenter schauspieler, die keine platten heldengeschichten erzählen wollen, sondern ihre charaktere zwischen licht und schatten auszubalancieren wissen.': 2,\n",
+ " 'hier greifen sie zusätzlich auf die referenz zu schauspielidolen jener zeit zurück und ziehen ihre rollen auf eine andere ebene, eine des selbstkommentars.': 2,\n",
+ " 'tom hardy arbeitet dabei vor allem mit der faszination seines johnny für marlon brandos gleichnamige figur in „der wilde“.': 2,\n",
+ " 'als der mechaniker diesen film erstmals im fernsehen sieht, springt ein funkeln in seinen blick.': 2,\n",
+ " 'wenn brando dann als anführer einer rockerbande auf die frage, wogegen er eigentlich rebelliere, antwortet: „was hast du im angebot?“, wiederholt hardy das mit leisem murmeln.': 2,\n",
+ " 'johnny hat sein vorbild gefunden, auch wenn er nur dessen autorität als rockerchef imitieren kann.': 2,\n",
+ " 'das sorglose des vorbilds liegt ihm allerdings nicht, und so ist genau das der wesenszug, den er an dem jungen benny, seiner zweiten hand im bikerklub, bewundert.': 2,\n",
+ " 'diesen jungen gibt austin butler, und man versteht spätestens jetzt, wen er sich nicht erst in „the bikeriders“ als darstellervorbild genommen hat.': 2,\n",
+ " 'von der wuscheligen blonden tolle bis zur lässigen pose erlebt man ihn als hommage an james dean, von dem butler sich auch gleich abgeschaut hat, wie man auf coolste art eine zigarette im mundwinkel hängen lässt.': 2,\n",
+ " 'weniger leicht zu entschlüsseln ist schon michael shannon, der die autoritären tendenzen jener männer in der bande verkörpert, die sich nach starken führern sehnen, und der „the walking dead“-star norman reedus, der das gegensatzpaar loyalität und irrsinn zusammenbinden darf.': 2,\n",
+ " 'die größte überraschung aber ist hier jodie comer.': 2,\n",
+ " 'gerade konnte man sie noch im kino in „the end we start from“ als britin mit baby gegen den untergang ihrer welt in der klimakatastrophe kämpfen sehen, da zeigt sie schon, wie man mit einem neuen akzent und einer bisher nicht eingenommenen haltung die komplette persönlichkeitsausstrahlung ändern kann.': 2,\n",
+ " 'comer legt kathy als furchtlose frau mit trockenem humor an, die genau beobachtet, in welche machtkämpfe sich ihr geliebter ziehen lässt und wie sich der bikerklub vom rennfahrerverein zur kriminellen organisation entwickelt.': 2,\n",
+ " 'freiheitsträume, lernt man hier, sind immer bedroht – und nur wer großes glück hat, kommt lebend davon.': 2,\n",
+ " 'die beiden am tresen haben die besten plätze.': 2,\n",
+ " 'ihr tisch steht direkt an der anrichteküche.': 2,\n",
+ " 'und das ist der ort, an dem bei julio pizarro die musik spielt.': 2,\n",
+ " 'mit beneidenswerter ruhe und gelassenheit bringt der peruaner auf der großen, von kupfernen wärmelampen beschienenen arbeitsfläche einen gang nach dem anderen auf die teller – und das paar am tresen hat uneingeschränkte sicht auf die filigrane handarbeit, mit der hier kleine kulinarische kunstwerke in serie entstehen.': 2,\n",
+ " 'mit ihrem gestreiften strickpullover und seinem poloshirt sehen die beiden nicht aus wie typische gourmet-gäste – aber sie sind nicht zum ersten mal hier.': 2,\n",
+ " 'der tisch am tresen ist etwas für stammgäste.': 2,\n",
+ " 'marcel dörflinger-oster platziert sie gerne in der nähe des chefs, wenn sie es möchten.': 2,\n",
+ " \"en club, c'est juste la ville.\": 2,\n",
+ " 'je pense que cela montre beaucoup de choses.': 2,\n",
+ " 'cet article (2/2) est issu du dossier': 2,\n",
+ " 'jamais dissous mais en sommeil depuis 2017, le gud avait annoncé son retour fin 2022.': 2,\n",
+ " \"connu pour ses actions violentes, le gud revient régulièrement sous les feux de l'actualité.\": 2,\n",
+ " 'parmi eux, marc de caqueray-valmenier, chef présumé des zouaves, condamné et incarcéré à plusieurs reprises ces dernières années.': 2,\n",
+ " 'het adviesbureau vroeg iedereen die wilde meewerken aan het onderzoek zich te melden en garandeerde anonimiteit.': 2,\n",
+ " 'ambtenaren – sommigen werken er al tientallen jaren – zouden het lastig vinden om elkaar aan te spreken op gedrag en binnen de „gelderse cultuur, waarin conflicten worden vermeden”, wordt dat al snel gezien als aanval.': 2,\n",
+ " 'rolf schuttenhelm': 2,\n",
+ " 'redacteur klimaat': 2,\n",
+ " 'danmark\\n \\n \\n 19. jun.': 2,\n",
+ " 'danmark\\n \\n 19. jun.': 2,\n",
+ " 'sundhed\\n \\n \\n 19. jun.': 2,\n",
+ " 'sundhed\\n \\n 19. jun.': 2,\n",
+ " 'arne: jeg var en af dem, der fulgte royal run på skærmen.': 2,\n",
+ " 'jeg indrømmer, at jeg flere gange tænkte: bare det var mig, der var med.': 2,\n",
+ " 'bare det var mig, der kunne løbe 5 km.': 2,\n",
+ " 'kan du give en opskrift på, hvordan jeg træner mig op til at løbe 5 km?': 2,\n",
+ " 'jeg er 55 år.': 2,\n",
+ " 'jeg går og cykler en del, men jeg er ikke vant til at løbe.': 2,\n",
+ " 'på kontoret sidder jeg foran en skærm det meste af dagen.': 2,\n",
+ " 'bente klarlund pedersen: sundhedsstyrelsen anbefaler, at vi motionerer mindst 30 minutter om dagen de fleste af ugens dage.': 2,\n",
+ " 'lad denne anbefaling være rammen for din målsætning om at løbe 5 km kontinuerligt.': 2,\n",
+ " 'hvis og når du opfylder ’30 minutter om dagen’ i rask gang, skal du langsomt konvertere gang til løb.': 2,\n",
+ " 'det er lodtrækning til tredje runde allerede 22. juli, altså inden fcm’s første opgør mod enten ballkani eller santa coloma.': 2,\n",
+ " 'klarer fcm sig videre til fjerde runde – også kaldet playoffrunden – i champions league-kvalifikation, vil holdet være sikret mindst en plads i europa leagues gruppespil.': 2,\n",
+ " 'også silkeborg if har været i bowlen i europa league-kvalifikationen.': 2,\n",
+ " 'pokalvinderen skal op mod molde i anden runde af europa leagues anden kvalifikationsrunde.': 2,\n",
+ " 'dansk økonomi kommer til at vokse med to procent i 2024.': 2,\n",
+ " 'det vurderer den internationale valutafond, imf, i en årlig gennemgang af dansk økonomi, som er blevet offentliggjort onsdag.': 2,\n",
+ " 'væksten vil blive drevet af medicinalindustrien og genåbningen af tyra-feltet, som er er et naturgasfelt.': 2,\n",
+ " 'det samme vurderede nationalbanken i sin seneste halvårlige vækstprognose for dansk økonomi, som udkom i marts.': 2,\n",
+ " 'her var det dog vurderingen, at økonomien vil vokse 2,4 procent i år.': 2,\n",
+ " 'imf er en organisation af 190 lande, som blandt andet arbejder for at fremme globalt pengesamarbejde og sikre finansiel stabilitet.': 2,\n",
+ " 'økonomer fra organisationen har brugt de seneste uger på at interviewe folk fra finansministeriet, nationalbanken og andre relevante myndigheder her i landet.': 2,\n",
+ " 'det har man gjort for at få et indtryk af, hvordan den danske økonomi har det.': 2,\n",
+ " 'på den baggrund kommer valutafonden også med anbefalinger til fremtiden.': 2,\n",
+ " 'den overordnede konklusion i rapporten er, at den danske økonomi står et robust sted.': 2,\n",
+ " 'kigger man lidt længere frem, er der udsigt til, at væksten i dansk økonomi kommer til at falde en anelse.': 2,\n",
+ " 'det skyldes, at eksportvæksten i medicinalindustrien vil aftage.': 2,\n",
+ " 'valutafonden har i sin gennemgang også noteret sig, at den ser tegn på, at arbejdsmarkedets momentum viser svaghedstegn.': 2,\n",
+ " 'beskæftigelsen har ellers trodset spådomme om tilbagegang i en lang periode.': 2,\n",
+ " 'derfor anbefales det også, at man gennemfører strukturelle reformer for at understøtte arbejdsmarkedet.': 2,\n",
+ " 'novellerne indeholdt meget voldsomme beskrivelser af kidnapninger af unge piger, som blev holdt indespærret, mens jeg-fortælleren forgreb sig på sine værgeløse ofre.': 2,\n",
+ " 'det nægter han.': 2,\n",
+ " 'havnen er en af vores vigtigste arbejdspladser, siger borgmesteren.': 2,\n",
+ " 'det sker i forbindelse med præsident putins besøg i pyongyang i dag.': 2,\n",
+ " '- rusland udelukker ikke et militærteknisk samarbejde med nordkorea i overensstemmelse med det dokument, der i dag er blevet underskrevet, siger vladimir putin.': 2,\n",
+ " 'elle en était toutefois sortie en 2017.': 2,\n",
+ " 'miljøaktivister har sprøjtet orange maling på flere af stenene på den verdenskendte stenformation stonehenge, der ligger omkring 135 kilometer fra london.': 2,\n",
+ " 'det fremgår onsdag af et opslag på det sociale medie x fra gruppen just stop oil.': 2,\n",
+ " 'her kan man se demonstranter i hvide t-shirts sprøjte maling på stonehenge, mens flere personer forsøger at stoppe dem.': 2,\n",
+ " 'to er blevet anholdt, oplyser lokalt politi i en meddelelse ifølge nyhedsbureauet reuters.': 2,\n",
+ " 'gruppen just stop oil er blevet kendt efter flere lignende aktioner i storbritannien.': 2,\n",
+ " 'just stop oil har blokeret trafikken på vigtige færdselsårer, forstyrret kulturbegivenheder og kastet suppe på et billede af den hollandske maler vincent van gogh.': 2,\n",
+ " 'gruppen ønsker, at den britiske regering stopper med at udvinde og afbrænde olie, gas og kul i 2030.': 2,\n",
+ " 'stonehenge er et forhistorisk monument, der ligger i wiltshire i det sydlige england.': 2,\n",
+ " 'det består af en formation af en række sten, der er over fire meter høje.': 2,\n",
+ " 'det er en af englands mest berømte attraktioner.': 2,\n",
+ " 'stenformationen menes at være bygget ad seks omgange mellem år 3000 og år 1500 før vores tidsregning.': 2,\n",
+ " 'stonehenge optræder på unescos verdensarvsliste sammen med andre attraktioner som taj mahal i indien og de store pyramider i giza i egypten.': 2,\n",
+ " 'det er organisationen english heritage, som står for at administrere og bevare stonehenge.': 2,\n",
+ " 'tegn et gratis prøveabonnement og få adgang til alt plus-indhold på ing, version2 og radar, helt uden binding eller betalingsoplysninger.': 2,\n",
+ " 'få en forlænget erhvervsprøvemed et erhvervsabonnement kan du få en forlænget prøveperiode.': 2,\n",
+ " 'indtast e-mail *': 2,\n",
+ " 'remove_circle': 2,\n",
+ " 'du accepterer vores abonnementsbetingelser for plus, når du tegner et abonnement eller prøveabonnement på plus.': 2,\n",
+ " 'læs betingelserne her.': 2,\n",
+ " 'du accepterer teknologiens mediehus’ brugerbetingelser og persondatapolitik.': 2,\n",
+ " 'du accepterer derudover følgende kontaktbetingelser: teknologiens mediehus må lejlighedsvis kontakte dig om arrangementer, konkurrencer, analyser, nyheder, job, undersøgelser og tilbud via e-mail.': 2,\n",
+ " 'i e-mails fra teknologiens mediehus kan der forekomme markedsføring fra samarbejdspartnere.': 2,\n",
+ " 'du kan til enhver tid indstille dine kontaktpræferencer, under menupunktet ‘tilladelser & services’ på din ing/profil.': 2,\n",
+ " 'har du allerede et plus-abonnement eller klip?': 2,\n",
+ " 'log ind east': 2,\n",
+ " 'da du er ved at tilmelde dig en gratis prøve beder vi dig hjælpe os med at gøre vores indhold mere relevant for dig, ved at vælge et eller flere emner der interesserer dig.': 2,\n",
+ " 'du skal vælge en adgangskode til når du fremover skal logge ind på din brugerkonto.': 2,\n",
+ " 'vælg adgangskode *': 2,\n",
+ " 'følger sagen.': 2,\n",
+ " 'årets tivolirevy består af lisbet dahl, thomas eje, rikke buch bendtsen, rikke bilde og mikkel becker hilgart.': 2,\n",
+ " 'herunder kan du læse b.t.s anmeldelse af årets tivolirevy.': 2,\n",
+ " 'læs også:\\xa0strategens bedste bud: her er 5 mulige vinderaktier': 2,\n",
+ " 'der er masser af gode muligheder for at spare penge på madbudgettet.': 2,\n",
+ " 'opdateres...': 2,\n",
+ " 'den historie kan du læse her.': 2,\n",
+ " '»at preppe er nok en opgave, der lægger sig oven i at drage omsorg for familien.': 2,\n",
+ " 'læs om det her.': 2,\n",
+ " 'lyt i spotify, på apple podcast eller ved at trykke play herunder.': 2,\n",
+ " \"i b.t.s podcast 'kongehuset bag kulissen' sætter b.t.s kongehusreporter silla bakalus sammen med eksperter hver uge fokus på ugens vigtigste royale historie.\": 2,\n",
+ " 'læs også:\\xa0globale kæmpeinvestorer skruer ned for tech - men festen er langt fra slut, mener dansk chefstrateg': 2,\n",
+ " 'læs også:\\xa0her mener dansk storbank, at der er mest aktiepotentiale lige nu': 2,\n",
+ " 'læs også:\\xa0dansk biotekselskab udsteder nye aktier - aktien banker op': 2,\n",
+ " '- hvorfor skulle han så tildække hendes hoved under hele forløbet.': 2,\n",
+ " 'hun har et pudebetræk over hovedet.': 2,\n",
+ " 'social- og boligministeren afviser enhver kritik af, at regeringen ville sløjfe aftalte bevillinger til en række integrationsprojekter.': 2,\n",
+ " 'det vakte vrede hos oppositionspartier og berørte organisationer.': 2,\n",
+ " 'politik\\n \\n \\n 20. jun.': 2,\n",
+ " 'politik\\n \\n 20. jun.': 2,\n",
+ " 'social- og boligministeren viste ingen tegn på fortrydelse eller forståelse, da hun onsdag eftermiddag skulle forklare sig på et velbesøgt samråd.': 2,\n",
+ " 'emnet for samrådet var de besparelser på politisk aftalte integrationsprojekter, som regeringen tidligere i år planlagde at gennemføre, men efter massiv kritik valgte at aflyse for 2024.': 2,\n",
+ " 'besparelserne er fortsat på bordet for 2025.': 2,\n",
+ " 'på samrådet deltog tre ministre, der i løbet af halvanden time skulle svare på forskellige versioner af spørgsmålet om, hvorvidt partierne på christiansborg kan regne med de aftaler, de indgår med regeringen.': 2,\n",
+ " 'partierne var oprørte over, at en aftale om integrationsindsatser indgået med socialministeren stod til at blive ophævet på grund af sparekrav vedtaget i en anden aftale om kriminalforsorgen med justitsministeren.': 2,\n",
+ " 'internationalt\\n \\n \\n 20. jun.': 2,\n",
+ " 'det oplyser det amerikanske stormcenter nhc torsdag.': 2,\n",
+ " 'stormen befinder sig omkring 200 kilometer øst for den mexicanske havneby tampico med vindstyrke på op til 80 kilometer i timen, lyder det fra nhc.': 2,\n",
+ " 'dog er albertos vindstyrke fortsat under orkanstyrke.': 2,\n",
+ " 'der er registreret mindst ét dødsfald som følge af stormen alberto.': 2,\n",
+ " 'det drejer sig om en 15-årig dreng, som blev revet med af strømmen i en flod og druknede ud for byen monterrey i delstaten nuevo leon.': 2,\n",
+ " 'det melder lokale beredskabsstyrker.': 2,\n",
+ " 'det oplyser dyre sønnicksen, vagtchef ved københavns politi, til ritzau.': 2,\n",
+ " 'politiet arbejder desuden på at få udleveret oplysninger om, hvem der har lejet bilen.': 2,\n",
+ " 'det regner nemlig med, at det er ham, som har kørt bilen i vandet.': 2,\n",
+ " 'i alt 52 personer i danmark er nu blevet smittet med salmonella.': 2,\n",
+ " 'det viser en opdateret opgørelse fra statens serum institut, som dækker over april, maj og juni, onsdag aften.': 2,\n",
+ " 'de syge er 32 mænd og 29 kvinder.': 2,\n",
+ " 'næsten halvdelen af de smittede var i region hovedstaden, og patienterne var op til 85 år gamle.': 2,\n",
+ " 'det vides endnu ikke, præcist hvor salmonellabakterien stammer fra, men fra ssi lød det i sidste uge, at de registrerede tilfælde formentlig kun er toppen af isbjerget.': 2,\n",
+ " 'i den forbindelse sagde luise müller også, at forklaringerne fra patienterne tydede på, at infektionerne stammede fra hakket oksekød.': 2,\n",
+ " 'det er dog endnu ikke bekræftet.': 2,\n",
+ " 'i maj blev 64 patienter i danmark smittet med en salmonellatype, der viste sig at stamme fra hakket oksekød fra england.': 2,\n",
+ " 'der kan være bakterier i hakket kød, som kan føre til sygdom.': 2,\n",
+ " 'det kan være salmonella, men det kan også være særligt farlige e. coli-bakterier.': 2,\n",
+ " 'derfor råder fødevarestyrelsen blandt andet til, at man køber hakket kød, som er specielt beregnet til tatar, hvis man ønsker at spise dette.': 2,\n",
+ " 'derudover bør man vaske hænder, inden man går i gang med madlavningen og efter at have rørt ved råt kød.': 2,\n",
+ " 'man bør også undgå at smage på råt kød, holde det adskilt fra den spiseklare mad samt gennemstege eller gennemkoge hakket kød.': 2,\n",
+ " 'salmonella findes hos dyr og kan smitte mennesker via fødevarer, som er forurenede med bakterien.': 2,\n",
+ " 'infektion med salmonella giver typisk diarré, ondt i maven, kvalme og feber.': 2,\n",
+ " 'ved alvorlige og vedvarende tilfælde opfordres man til at gå til lægen.': 2,\n",
+ " 'forhandlingerne om, hvordan danmark skal nå de klimamål, der er sat op, er i fuld gang.': 2,\n",
+ " 'men en af hovedpersonerne er sat ud af spillet på ubestemt tid.': 2,\n",
+ " 'det skriver han selv i et opslag på linkedin.': 2,\n",
+ " 'lars aagaard har endnu ikke fået en diagnose og ved derfor heller ikke, hvor længe han skal være indlagt.': 2,\n",
+ " 'lars aagaard er en af de fem ministre, der repræsenterer regeringen i forhandlingerne om den såkaldte grønne trepart, der gerne skal munde ud i en aftale, der mindsker landbrugets co2-udledning de kommende år.': 2,\n",
+ " 'de øvrige parter er landbruget, fagforeninger, kommunerne og miljøorganisationer.': 2,\n",
+ " 'forhandlingerne ledes af den tidligere formand for folketinget henrik dam kristensen.': 2,\n",
+ " 'forhandlingerne begyndte i januar, og planen er, at der skal ligge et udspil klar inden udgangen af denne måned.': 2,\n",
+ " 'min kærlighed til ’the boys’ er båret af den skarpe politiske satire, den elegante kropshorror og den kombination af frastødelse og ømhed, karaktererne vækker.': 2,\n",
+ " 'der er mindre af det hele i sæson 4.': 2,\n",
+ " 'sådan forløb kampen:': 2,\n",
+ " 'de tyske værter er som det første hold klar til ottendedelsfinalerne ved em.': 2,\n",
+ " 'efter at have slået skotland 5-1 i åbningskampen leverede tyskerne endnu en overbevisende præstation onsdag.': 2,\n",
+ " 'ungarn blev slået 2-0, og med seks point efter to gruppekampe er tyskerne sikret avancement.': 2,\n",
+ " 'efter en god og optimistisk ungarsk start var det tyskerne, som satte sig tungt på kampen.': 2,\n",
+ " 'med erfarne toni kroos som dirigent spillede tyskerne på de mange offensive tangenter, der er på holdet.': 2,\n",
+ " 'ungarn havde travlt med at afvise de tyske tilnærmelser tæt på eget felt, mens den hurtige tyske bagkæde dygtigt fik lukket ned for de sporadiske kontraforsøg fra ungarerne.': 2,\n",
+ " 'ilkay gündogan kæmpede hårdt for en bold inde i feltet, og efter lidt klumpspil fik han bugseret bolden hen til musiala, som i relativt fri position kunne sparke bolden i kassen.': 2,\n",
+ " 'det kunne være blevet til flere tyske scoringer før pausen, men ungarn havde også et par chancer.': 2,\n",
+ " 'manuel neuer måtte blandt andet diske op med en stor redning på et frisparksforsøg fra liverpools dominik szoboszlai.': 2,\n",
+ " 'i halvlegens tillægstid fik ungarn bolden i mål, men linjedommeren vinkede korrekt for offside.': 2,\n",
+ " 'den tyske dominans aftog en smule efter pausen.': 2,\n",
+ " 'ungarerne fornemmede, at der var muligheder for at arbejde sig ind i kampen.': 2,\n",
+ " 'især roland sallai voldte tyskland en del problemer.': 2,\n",
+ " 'den hurtige offensivspiller lagde sig ofte ud til tyskernes højreback joshua kimmich og fik skabt farlige situationer med både driblinger og indlæg.': 2,\n",
+ " 'bedst som ungarn vejrede morgenluft, viste værtsnationen igen, hvorfor den skal regnes som en potentiel europamester.': 2,\n",
+ " 'efter 66 minutter kombinerede man på forbilledlig vis, og slutteligt blev bolden lagt til rette for gündogan skråt tilbage i feltet.': 2,\n",
+ " 'med indersiden fordoblede han føringen og punkterede den ungarske tro på point.': 2,\n",
+ " 'på cruisekontrol styrede tyskerne mod sejren, uden at ungarn på noget tidspunkt var tæt på at ændre på udfaldet.': 2,\n",
+ " 'træner julian nagelsmann kunne lade stuttgart-spillerne i truppen komme på banen til hyldest på deres normale hjemmebane og lidt em-minutter.': 2,\n",
+ " 'tyskland skal i sidste gruppekamp møde schweiz i frankfurt.': 2,\n",
+ " '- kan man afvise, at det forholder sig på den måde?': 2,\n",
+ " 'med vores brevkasse spørg videnskaben kan du stille spørgsmål til forskerne om alt fra prutter og sjove bynavne til kvantecomputere og livets oprindelse.': 2,\n",
+ " 'vi vælger de bedste spørgsmål og kvitterer med en videnskab.dk-t-shirt.': 2,\n",
+ " 'det kan du læse mere om her.': 2,\n",
+ " '/ritzau/afp': 2,\n",
+ " 'sie ist in den herzen der menschen verwurzelt.': 2,\n",
+ " 'es müsse eine alternative für die hamas auf politischer ebene gefunden werden, um sie im gazastreifen zu ersetzen, forderte hagari in dem interview weiter.': 2,\n",
+ " 'über die zerstörung der hamas zu reden, führe die öffentlichkeit in die irre.': 2,\n",
+ " 'jamal musiala ist so frei, ilkay gündogan auch – und kai havertz fühlt sich als stürmer immer wohler.': 2,\n",
+ " '19 juni 2024': 2,\n",
+ " '„het zal wel loslopen.”': 2,\n",
+ " 'nu ga ik tot het gaatje met die lui.': 2,\n",
+ " 'ze zeiden dat beveiliging niet nodig was, terwijl ze dit wisten.': 2,\n",
+ " 'guus dietvorst': 2,\n",
+ " 'redacteur politiek': 2,\n",
+ " 'fleur launspach': 2,\n",
+ " 'correspondent vk en ierland': 2,\n",
+ " 'power up with unlimited access to wired.': 2,\n",
+ " \"get best-in-class reporting that's too important to ignore for just $2.50 $1 per month for 1 year.\": 2,\n",
+ " 'includes unlimited digital access and exclusive subscriber-only content.': 2,\n",
+ " '15 hours ago': 2,\n",
+ " 'by\\xa0hafsa khalil,\\xa0bbc news': 2,\n",
+ " 'the war in ukraine has shifted the balance of power between moscow, pyongyang and beijing': 2,\n",
+ " 'new episodes every week.': 2,\n",
+ " 'june 19, 2024': 2,\n",
+ " 'hbr learning': 2,\n",
+ " 'digital intelligence course': 2,\n",
+ " 'accelerate your career with harvard managementor®.': 2,\n",
+ " 'hbr learning’s online leadership training helps you hone your skills with courses like digital intelligence .': 2,\n",
+ " 'earn badges to share on linkedin and your resume.': 2,\n",
+ " 'access more than 40 courses trusted by fortune 500 companies.': 2,\n",
+ " \"excel in a world that's being continually transformed by technology.\": 2,\n",
+ " 'profitez du pack canal + pour regarder espagne - italie en streaming': 2,\n",
+ " 'profitez de ce bon plan molotov pour regarder en streaming espagne - italie': 2,\n",
+ " 'on a l’impression de se partager un secret.': 2,\n",
+ " \"(laurent le crabe/l'équipe)\": 2,\n",
+ " 'dominique de villepin était notamment interrogé sur la prise de position de serge klarsfeld, historien rescapé de la shoah, qui a annoncé quelques jours plus tôt qu’il voterait pour le rn.': 2,\n",
+ " 'notre librairie de quartier, on l’aime.': 2,\n",
+ " 'décryptage.': 2,\n",
+ " '«\\xa0j’étais tellement content d’être face à clotaire.': 2,\n",
+ " 'enormes carteles con las fotos de los dos líderes adornaban los edificios circundantes durante la ceremonia de bienvenida.': 2,\n",
+ " 'pese a la situación económica, pyongyang parece no haber escatimado en recursos para esta visita, con la esperanza, por supuesto, de que dé sus frutos, indica khalil.': 2,\n",
+ " 'putin le obsequió a su homólogo un lujoso automóvil ruso aurus, una daga de almirante y un juego de té, informaron los medios estatales rusos, citando al asistente presidencial yuri ushakov.': 2,\n",
+ " 'esta prevista una fiesta de té y un concierto de gala en la noche.': 2,\n",
+ " 'rejser\\n \\n \\n 20. jun.': 2,\n",
+ " 'rejser\\n \\n 20. jun.': 2,\n",
+ " '»vi har fundet en god midlertidig afløser for lisbet dahl i lone rødbroe, der gennem mange år har underholdt på førende revyscener rundt om i danmark.': 2,\n",
+ " 'foreningen bag folkemødet på bornholm skal have ny formand.': 2,\n",
+ " 'den hidtidige formand, vibe klarup, stopper på posten, som hun har bestridt de seneste fire år.': 2,\n",
+ " 'det fremgår af en pressemeddelelse fra foreningen folkemødet.': 2,\n",
+ " 'om beslutningen siger den afgående formand:': 2,\n",
+ " 'hun er generalsekretær i amnesty international danmark og overtog posten som formand i 2020 efter jann sjursen.': 2,\n",
+ " 'folkemødets bestyrelse skal nu på jagt efter en efterfølger til formandsposten.': 2,\n",
+ " 'bestyrelsen har konstitueret sig med et delt formandskab mellem de to hidtidige næstformænd, søs marie serup og carsten grønning.': 2,\n",
+ " 'sport\\n \\n \\n 20. jun.': 2,\n",
+ " 'sport\\n \\n 20. jun.': 2,\n",
+ " 'ifølge det serbiske medie rts opfordrede de to fangrupperinger til drab på serberne.': 2,\n",
+ " '»først og fremmest vil jeg takke vores fans for støtten i kampen mod england, og jeg håber på, vi kan slå slovenien.': 2,\n",
+ " 'men det, der skete, er skandaløst, og vi vil bede uefa om sanktioner.': 2,\n",
+ " 'serbien spiller torsdag en potentiel skæbnekamp mod slovenien i danmarks gruppe, og på trods af truslen om at trække sig er der intet, der endnu tyder på, at serberne ikke stiller til kampstart.': 2,\n",
+ " 'epidemi af kødædende bakterier har': 2,\n",
+ " 'ramt danmark.': 2,\n",
+ " 'hundreder betaler af': 2,\n",
+ " 'på »coronagæld« med sygdom og død': 2,\n",
+ " 'europa sover, siger mærsks': 2,\n",
+ " 'chef: »jeg er klart bekymret«': 2,\n",
+ " 'medier: ukraines sikkerhedstjeneste': 2,\n",
+ " 'slår til igen – forsøger at lamme': 2,\n",
+ " 'europas kokainkonge afslører sig selv:': 2,\n",
+ " 'hans private billeder og ord viser os': 2,\n",
+ " 'sandheden om livet som gangster': 2,\n",
+ " 'erhvervslivet jubler: »det er en': 2,\n",
+ " 'forbedring i forhold til, at det bare': 2,\n",
+ " 'er noget, skat har fundet på«': 2,\n",
+ " 'forsvarer: mette': 2,\n",
+ " 'frederiksen fik': 2,\n",
+ " 'ikke piskesmæld': 2,\n",
+ " 'redaktør roser københavns': 2,\n",
+ " 'nye stadsarkitekt.': 2,\n",
+ " 'er alligevel et problem': 2,\n",
+ " 'strejke hos postnord forsinker brevforsendelser i flere dage': 2,\n",
+ " '»jeg var tæt på kanten«: pludselig': 2,\n",
+ " 'blev hans højre underben': 2,\n",
+ " 'angrebet af kødædende bakterier': 2,\n",
+ " 'serbien fra danmarks gruppe': 2,\n",
+ " 'truer med at trække sig fra em': 2,\n",
+ " 'korrespondent spiste': 2,\n",
+ " 'forbudte nudler forkert.': 2,\n",
+ " 'nu spiser han dem igen': 2,\n",
+ " 'dansk socialt medie': 2,\n",
+ " 'er tilbage: 10.000': 2,\n",
+ " 'tilmeldinger på seks': 2,\n",
+ " 'til tivolirevyen': 2,\n",
+ " 'folkemødet trækker sig': 2,\n",
+ " 'særdeles dyster læsning for': 2,\n",
+ " 'rishi sunak: han kan blive': 2,\n",
+ " 'den første nogensinde': 2,\n",
+ " 'de har udsigt til danmarks': 2,\n",
+ " 'højeste løn.': 2,\n",
+ " 'oskar allerslev': 2,\n",
+ " 'valgte uddannelsen for': 2,\n",
+ " 'pengenes skyld': 2,\n",
+ " 'giver forskere deres bud på hvorfor': 2,\n",
+ " 'se de »barbariske« scener: kinas': 2,\n",
+ " '»pirater« angreb med økser og spyd': 2,\n",
+ " 'festen var præcis, som den': 2,\n",
+ " 'skulle være.': 2,\n",
+ " 'en skaldet engelsk': 2,\n",
+ " 'fodboldfan nåede grænsen ved': 2,\n",
+ " 'en lille, lyshåret, tysk ung kvinde': 2,\n",
+ " 'adam holm advarer': 2,\n",
+ " 'om »situationens': 2,\n",
+ " 'alvor«: »nu er': 2,\n",
+ " 'her er formkurven hos de': 2,\n",
+ " 'borgerlige: én har helt uventet': 2,\n",
+ " 'grund til at være bekymret': 2,\n",
+ " 'jeg er sådan set glad for, at denne': 2,\n",
+ " 'film findes, men hold kæft hvor': 2,\n",
+ " 'er disse skuespillere irriterende': 2,\n",
+ " 'bemærkelsesværdig rekord for danskere i job': 2,\n",
+ " 'der findes et hav af film om': 2,\n",
+ " 'anden verdenskrig.': 2,\n",
+ " 'sikkert få dig på grådens rand': 2,\n",
+ " 'forud for debat': 2,\n",
+ " 'antal unge uden': 2,\n",
+ " 'uddannelse og job': 2,\n",
+ " 'stiger – tesfaye': 2,\n",
+ " 'varsler udspil': 2,\n",
+ " 'firedobler overskuddet': 2,\n",
+ " 'berlingske erfarer: så meget': 2,\n",
+ " 'lettes virksomhedernes skat i dag': 2,\n",
+ " 'danmark var i problemer – nu venter': 2,\n",
+ " 'favoritterne: »vi skal have drømmen«': 2,\n",
+ " 'hussalget er nu': 2,\n",
+ " 'over niveauet i': 2,\n",
+ " 'tiden før corona': 2,\n",
+ " 'nu venter det': 2,\n",
+ " 'ubetinget stærkeste': 2,\n",
+ " 'hold i gruppen:': 2,\n",
+ " '»danmark får det': 2,\n",
+ " '150.000 pakker jodtabletter': 2,\n",
+ " 'på vej til apotekerne': 2,\n",
+ " 'nu skal danskerne preppe, mens': 2,\n",
+ " 'myndighederne halter bagefter: troels': 2,\n",
+ " 'lund afviser, at vi er uforberedte': 2,\n",
+ " 'jobbet er kun et hak bedre': 2,\n",
+ " 'end at forsvare olieselskaber': 2,\n",
+ " 'og tobaksindustrien – men': 2,\n",
+ " 'det kan også være et': 2,\n",
+ " 'drømmeexit fra dansk politik': 2,\n",
+ " 'midt i afgørende forhandlinger: klimaminister': 2,\n",
+ " 'indlagt med »voldsomme rygsmerter«': 2,\n",
+ " 'rusland og nordkorea vil': 2,\n",
+ " 'omstyrte verdensordenen.': 2,\n",
+ " 'bestyrelse enige: grønt lys for elge i nordsjælland': 2,\n",
+ " 'en af sunaks livvagter er': 2,\n",
+ " 'anholdt og suspenderet': 2,\n",
+ " 'efter mistanke om': 2,\n",
+ " 'væddemål om valgdato': 2,\n",
+ " '78-årig skuespiller har det efter omstændighederne godt, oplyser kulturdirektør i tivoli.': 2,\n",
+ " 'kulturdirektør frederik wiedemann siger, at 78-årige dahl \"efter omstændighederne har det godt\" og \"vender tilbage til revyen, når hun er rask igen\".': 2,\n",
+ " '- vi har fundet en god midlertidig afløser for lisbet dahl i lone rødbroe, der gennem mange år har underholdt på førende revyscener rundt om i danmark.': 2,\n",
+ " 'det er en løsning, som lisbet dahl også er glad for, siger frederik wiedemann.': 2,\n",
+ " 'lisbeth dahl har medvirket i et stort antal film, teaterstykker og revyer, og hun er ifølge tivolis hjemmeside instruktør og kunstnerisk leder af årets tivolirevy.': 2,\n",
+ " 'året før - i 2021 - havde skuespilleren ligeledes en sygeperiode under cirkusrevyen.': 2,\n",
+ " 'det skyldes dengang stress \"efter et sygdomsforløb, der har tæret på kræfterne\", blev det oplyst i en pressemeddelelse.': 2,\n",
+ " 'den første harry potter-bog blev i 1997 trykt i 500 eksemplarer, da der var usikkerhed om dens potentiale.': 2,\n",
+ " 'en sjælden førsteudgave af harry potter-bogen \"harry potter og de vises sten\" er blevet solgt på en auktion i skotland for 45.201 pund - svarende til knap 400.000 danske kroner.': 2,\n",
+ " 'det skriver nyhedsbureauet dpa.': 2,\n",
+ " 'i første omgang blev bogen i 1997 blot trykt i 500 eksemplarer, fordi der var usikkerhed om, hvor populær den ville blive.': 2,\n",
+ " 'bogserien, som den britiske forfatter j.k. rowling står bag, viste sig dog at blive ekstremt populær på verdensplan.': 2,\n",
+ " 'bbc har tidligere skrevet, at bogserien er blandt de bedst sælgende nogensinde og har solgt over 600 millioner eksemplarer på verdensplan.': 2,\n",
+ " 'derudover er den siden blevet filmatiseret.': 2,\n",
+ " 'bogen var spået til at blive solgt for mellem 40.000 og 60.000 pund.': 2,\n",
+ " 'den blev solgt onsdag hos auktionshuset lyon & turnbull i hovedstaden edinburgh.': 2,\n",
+ " '\"harry potter og de vises sten\" er den første i bogserien på i alt syv bøger.': 2,\n",
+ " 'her følger man drengen harry, der viser sig at være troldmand og begynder på skolen hogwarts.': 2,\n",
+ " 'derudover er der udgivet andre bøger i samme univers.': 2,\n",
+ " '- en førsteudgave af \"harry potter og de vises sten\" er en usædvanligt sjælden bog at finde i enhver stand.': 2,\n",
+ " 'og en i så fremragende stand kunne godt blive kaldt juvelen i enhver harry potter-samlers krone, har cathy marsden, chef for bøger og manuskripter hos auktionshuset, udtalt.': 2,\n",
+ " 'ud over harry potter-bogen blev der også solgt andre bøger på samme auktion.': 2,\n",
+ " 'det gjaldt blandt andet en kopi af ian flemings \"casino royale\", som er den første roman i spionserien om james bond, der også er blevet filmatiseret.': 2,\n",
+ " 'den var vurderet til at koste mellem 30.000 og 50.000 pund og blev solgt for 38.951 pund - knap 344.000 danske kroner, skriver dpa.': 2,\n",
+ " 'ifølge cathy marsden er værker af \"litterære giganter\" som rowling og ian fleming fortsat meget populære, når de skal på auktion.': 2,\n",
+ " 'på auktionen kom en førsteudgave af bogen \"when we were very young\" af peter plys-forfatteren a.': 2,\n",
+ " 'a. milne også under hammeren.': 2,\n",
+ " 'den blev solgt for 15.120 pund - omkring 133.000 kroner.': 2,\n",
+ " 'mod tidligere 3,5-5 pct.': 2,\n",
+ " 'mod tidligere 1,7-1,8 mia.': 2,\n",
+ " '18+ | spil ansvarligt | regler og vilkår gælder | stopspillet – ring til 70 22 28 25 | udeluk dig via rofus\\xa0|\\xa0der tages forbehold for fejl og ændringer.': 2,\n",
+ " 'dagens øvrige kampe': 2,\n",
+ " 'ballerina sko er et ikonisk valg, der kombinerer elegance og komfort på fornem vis.': 1,\n",
+ " 'disse sko er kendetegnet ved deres flade hæl og spidse tå, hvilket giver en raffineret og feminin silhuet.': 1,\n",
+ " 'samtidig er de utroligt behagelige at have på, takket være deres fleksible materialer og polstrede indersål.': 1,\n",
+ " 'uanset om du skal til en særlig begivenhed eller blot ønsker et stilfuldt, men behageligt fodtøj til hverdagsbrug, er ballerina sko et oplagt valg.': 1,\n",
+ " 'de fås i et bredt udvalg af farver og designs, så du nemt kan finde et par, der passer perfekt til din personlige stil.': 1,\n",
+ " 'de bedste ballerina sko kendetegnes ved deres komfort og støtte.': 1,\n",
+ " 'de skal have en fleksibel, men stabil sål, der giver god affjedring og støtte til foden.': 1,\n",
+ " 'materialet bør være blødt og åndbart, så foden kan bevæge sig frit uden at blive irriteret.': 1,\n",
+ " 'desuden er det vigtigt, at skoen passer perfekt til foden og ikke glider eller gnaver.': 1,\n",
+ " 'hvis du leder efter de bedste ballerina sko, anbefaler vi at du køber de bedste ballerina sko online.': 1,\n",
+ " 'her finder du et stort udvalg af kvalitetssko, der lever op til disse krav.': 1,\n",
+ " 'det er vigtigt at finde den rette størrelse og pasform, når du køber ballerina sko online.': 1,\n",
+ " 'måling af foden er nøglen til at finde den perfekte størrelse.': 1,\n",
+ " 'brug en lineal til at måle længden og bredden af din fod, og sammenlign målingerne med størrelsesguiden fra den webshop, du køber fra.': 1,\n",
+ " 'nogle webshops tilbyder også muligheden for at gemme dine mål, så du nemt kan finde den rette størrelse næste gang.': 1,\n",
+ " 'derudover er det en god idé at kigge på anmeldelser af skoenes pasform, så du ved, om de falder lille eller stor i størrelsen.': 1,\n",
+ " 'hvis du er i tvivl, kan du også overveje at købe smykkeskrin med ballerina i mange varianter, så du kan prøve flere størrelser.': 1,\n",
+ " 'ballerina sko fremstilles typisk af forskellige materialer, som hver især tilbyder forskellige fordele.': 1,\n",
+ " 'nogle af de mest populære materialer inkluderer: læder – et klassisk og holdbart materiale, som giver god støtte og pasform.': 1,\n",
+ " 'lædersko er ofte mere kostbare, men kan holde i mange år.': 1,\n",
+ " 'kanvas – et let og åndbart materiale, der er ideelt til dansere, der laver mange bevægelser.': 1,\n",
+ " 'kanvas sko er ofte mere overkommelige i pris.': 1,\n",
+ " 'satin – et elegant og feminint materiale, som giver en flot finish på sko.': 1,\n",
+ " 'satin sko er dog mindre holdbare end læder- og kanvasmodeller.': 1,\n",
+ " 'uanset hvilket materiale du vælger, er det vigtigt at finde sko, der passer godt og føles komfortable at have på.': 1,\n",
+ " 'det er den bedste måde at sikre, at dine ballerina sko holder i lang tid.': 1,\n",
+ " 'ballerina sko er et alsidigt valg, der kan bæres til mange forskellige lejligheder.': 1,\n",
+ " 'uanset om du skal til en uformel sammenkomst, en mere formel begivenhed eller blot ønsker at se stilfuld ud til hverdag, findes der ballerina sko, der passer perfekt.': 1,\n",
+ " 'de flade sko er komfortable at gå i hele dagen og giver et elegant, feminint udtryk.': 1,\n",
+ " 'vælg mellem forskellige materialer, farver og detaljer for at finde det rette par, der matcher din personlige stil og påklædning.': 1,\n",
+ " 'pleje og vedligeholdelse af dine ballerina sko er vigtig for at sikre, at de holder længe og ser pæne ud.': 1,\n",
+ " 'rengør dine sko regelmæssigt med en blød børste og et mildt rengøringsmiddel.': 1,\n",
+ " 'undgå at bruge for meget vand, da det kan beskadige materialet.': 1,\n",
+ " 'lad dine sko lufttørre i stedet for at bruge en tørretumbler.': 1,\n",
+ " 'opbevar dine sko i deres originale æske eller en anden beskyttende emballage, når de ikke er i brug.': 1,\n",
+ " 'dette hjælper med at bevare formen og forhindrer, at de bliver beskadiget.': 1,\n",
+ " 'følg også producentens anvisninger for pleje og vedligeholdelse, da forskellige materialer kan kræve forskellige metoder.': 1,\n",
+ " 'ballerina sko kommer i et bredt udvalg af stilarter og trends.': 1,\n",
+ " 'de klassiske ballerina sko med flad hæl og afrundet tå er stadig populære, men der er også kommet flere moderne varianter på markedet.': 1,\n",
+ " ...})"
+ ]
+ },
+ "execution_count": 752,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "total_sent_count"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Counter({'18 jun.video': 34,\n",
+ " '17 jun.video': 22,\n",
+ " 'saltar recomendamos y continuar leyendo': 19,\n",
+ " 'recomendamos': 19,\n",
+ " 'final de recomendamos': 19,\n",
+ " 'blijf op de hoogte': 18,\n",
+ " 'haz clic aquí para leer más historias de bbc news mundo.': 18,\n",
+ " 'y recuerda que puedes recibir notificaciones en nuestra app.': 18,\n",
+ " 'descarga la última versión y actívalas.': 17,\n",
+ " '18 jun.binnenland': 16,\n",
+ " 'ongeldig e-mailadres.': 14,\n",
+ " 'vul nogmaals in aub.': 14,\n",
+ " 'lees\\xa0hier\\xa0ons privacybeleid.': 14,\n",
+ " 'bekijk meer van': 14,\n",
+ " 'wil je op de hoogte blijven over alles rondom oorlog in oekraïne,\\n schrijf je dan in voor onze blijf op de hoogte nieuwsbrief.': 13,\n",
+ " 'veilig betalen': 13,\n",
+ " '14 dagen bedenktijd': 13,\n",
+ " '€ 79.99€ 189.95': 13,\n",
+ " '€ 139.99€ 229.95': 13,\n",
+ " '€ 54.99€ 99.99': 13,\n",
+ " '€ 24.99€ 79.95': 13,\n",
+ " 'meer van de telegraaf webshop': 13,\n",
+ " 'lyt hos apple podcast, spotify eller ved at klikke play herunder.': 13,\n",
+ " 'sabrina günther': 12,\n",
+ " 'internationalt\\n \\n 19. jun.': 11,\n",
+ " 'menuga naar het menuga naar de inhoud': 10,\n",
+ " 'sönke sievers': 10,\n",
+ " 'kokken hannah grant giver sig sine bedste sparetip til madbudgettet og sit bedste tip til prepping-mad i den seneste udgave af podcasten spar kassen.': 10,\n",
+ " 'premiumhet beste van de telegraaf': 9,\n",
+ " 'avis des utilisateurs': 9,\n",
+ " 'artiklen er føjet til din læseliste\\n du har ulæste artikler på din læseliste': 9,\n",
+ " '19 junio 2024': 9,\n",
+ " 'annals of celebrity': 8,\n",
+ " 'design et ergonomie': 8,\n",
+ " 'artiklen er oprindelig udgivet af euroinvestor.': 8,\n",
+ " 'caractéristiques techniques': 7,\n",
+ " \"comparaison avec d'autres modèles\": 7,\n",
+ " 'de krantvideopodcastpuzzels\\xa016\\xa0°c\\xa08\\xa0kmklantenservice': 6,\n",
+ " 'nieuwsbinnenland': 6,\n",
+ " 'premium05:40binnenland': 6,\n",
+ " 'performances audio': 6,\n",
+ " 'points forts\\xa0:': 5,\n",
+ " 'pour quel type de peau ?': 5,\n",
+ " '18 junio 2024': 5,\n",
+ " 'our flagship newsletter highlights the best of the new yorker, including top stories, fiction, humor, and podcasts.': 4,\n",
+ " 'e-mail address': 4,\n",
+ " 'by signing up, you agree to our user agreement and privacy policy & cookie statement.': 4,\n",
+ " 'this site is protected by recaptcha and the google privacy policy and terms of service apply.': 4,\n",
+ " 'the strange journey of john lennon’s stolen patek philippe watch': 4,\n",
+ " 'for decades, yoko ono thought that the birthday gift was in her dakota apartment.': 4,\n",
+ " 'but it had been removed and sold—and now awaits a court ruling in geneva.': 4,\n",
+ " 'by jay fielden': 4,\n",
+ " 'letter from ecuador': 4,\n",
+ " 'ecuador’s risky war on narcos': 4,\n",
+ " 'does president daniel noboa’s campaign against drug gangs imperil the democracy he claims to defend?': 4,\n",
+ " 'by jon lee anderson': 4,\n",
+ " 'kanye west bought an architectural treasure—then gave it a violent remix': 4,\n",
+ " 'how the hip-hop star’s beautiful, dark, twisted fantasy turned a beach house in malibu, designed by the japanese master tadao ando, into a ruin.': 4,\n",
+ " 'by ian parker': 4,\n",
+ " 'u.s. journal': 4,\n",
+ " 'ghosts on the water': 4,\n",
+ " 'glass eels are mysterious creatures—and worth a fortune to those who catch them.': 4,\n",
+ " 'by paige williams': 4,\n",
+ " 'offer ends 2nd of july 2024.': 4,\n",
+ " '6 hours ago': 4,\n",
+ " '4 hours ago': 4,\n",
+ " 'privé nieuwsbrief': 4,\n",
+ " 'dagelijks het laatste nieuws over de sterren en royals.': 4,\n",
+ " 'premium00:02sterren': 4,\n",
+ " 'ik betwijfel het ten zeerste.': 4,\n",
+ " 'de krantvideopodcastpuzzels\\xa017\\xa0°c\\xa018\\xa0kmklantenservice': 4,\n",
+ " 'wil je op de hoogte blijven over alles rondom oorlog israël,\\n schrijf je dan in voor onze blijf op de hoogte nieuwsbrief.': 4,\n",
+ " \"qualité de l'image\": 4,\n",
+ " 'fonctionnalités smart tv': 4,\n",
+ " 'contenu conçu et proposé par digital content expert pour le figaro services.': 4,\n",
+ " 'internationalt\\n \\n 20. jun.': 4,\n",
+ " 'les avantages\\xa0:': 4,\n",
+ " 'les inconvénients\\xa0:': 4,\n",
+ " 'skuespilleren lisbet dahl er sygemeldt og må holde pause fra årets tivolirevy.': 4,\n",
+ " 'tivolirevyen spiller igen torsdag aften og til og med 14. juli.': 4,\n",
+ " 'internationalt\\n \\n \\n 19. jun.': 3,\n",
+ " \"autissier/l'équipe)\": 3,\n",
+ " 'ähnlich äußerte sich die sprecherin des weißen hauses, karine jean-pierre.': 3,\n",
+ " 'find anything you save across the site in your account': 3,\n",
+ " 'daily cartoon': 3,\n",
+ " 'june 18, 2024': 3,\n",
+ " 'buy new yorker cartoons »': 3,\n",
+ " 'how to motivate me during an exercise class.': 3,\n",
+ " 'why you, my roommate, should adopt a dog.': 3,\n",
+ " 'to all the women in bathroom lines we’ve befriended before.': 3,\n",
+ " 'reasons i was crying on the subway.': 3,\n",
+ " 'cult-activities coördinator seeks a new gig.': 3,\n",
+ " 'publishing a book, by the numbers.': 3,\n",
+ " 'enter the cartoon caption contest for a chance to appear in the magazine.': 3,\n",
+ " 'follow @newyorkercartoons on instagram and subscribe to the new yorker for more funny stuff.': 3,\n",
+ " 'subscribe today.': 3,\n",
+ " '3 hours ago': 3,\n",
+ " '9 hours ago': 3,\n",
+ " 'bbc indepth is the new home on the website and app for the best analysis and expertise from our top journalists.': 3,\n",
+ " 'under a distinctive new brand, we’ll bring you fresh perspectives that challenge assumptions, and deep reporting on the biggest issues to help you make sense of a complex world.': 3,\n",
+ " 'and we’ll be showcasing thought-provoking content from across bbc sounds and iplayer too.': 3,\n",
+ " 'we’re starting small but thinking big, and we want to know what you think - you can send us your feedback by clicking on the button below.': 3,\n",
+ " '5 hours ago': 3,\n",
+ " '16 hours ago': 3,\n",
+ " '10 hours ago': 3,\n",
+ " '05:40sterren': 3,\n",
+ " '18 jun.sterren': 3,\n",
+ " 'nieuwsbuitenland': 3,\n",
+ " '1 uur geledenin buitenland': 3,\n",
+ " '17 jun.buitenland': 3,\n",
+ " '05:32buitenland': 3,\n",
+ " '10:33buitenland': 3,\n",
+ " '07:00buitenland': 3,\n",
+ " '05:37buitenland': 3,\n",
+ " 'foto familie tantesh': 3,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von facebook, der den artikel ergänzt und von der redaktion empfohlen wird.': 3,\n",
+ " '-800 euros sur la philips 55oled808': 3,\n",
+ " 'promo sur le intex purespa': 3,\n",
+ " 'la tv qled tcl à moitié prix\\xa0!': 3,\n",
+ " '-1000 euros sur la samsung tq55s95c': 3,\n",
+ " 'promo sur le marantz cinema 60 dab': 3,\n",
+ " 'david lindenfeld': 3,\n",
+ " 'dans la zone': 3,\n",
+ " 'fc midtjylland møder enten ballkani fra kosovo eller santa coloma fra andorra i champions league-kvalifikationens anden runde.': 3,\n",
+ " 'det blev afgjort ved en lodtrækning i uefas hovedkvarter nyon onsdag ved middagstid.': 3,\n",
+ " 'de to mulige modstandere dyster 9.-10. juli og 16.-17. juli, og den samlede vinder gå videre til et dobbeltopgør mod den danske mester, som er seedet i anden runde.': 3,\n",
+ " 'opgørene i anden runde står til at blive afviklet 23.-24. juli og 30.-31. juli, og fc midtjylland starter ude og slutter af hjemme i herning.': 3,\n",
+ " 'ballkani må betegnes som klar favorit til at skulle en tur til det midtjyske.': 3,\n",
+ " 'santa coloma har således tabt samtlige sine hidtidige 16 opgør i de europæiske turneringer.': 3,\n",
+ " 'ballkani har klaret sig bedre, men har i to forsøg endnu ikke klaret sig videre fra champions league-kvalifikationens første runde.': 3,\n",
+ " 'til gengæld er holdet gået videre til conference league-gruppespil i de to seneste sæsoner.': 3,\n",
+ " 'her er det blevet til sejre over tyrkiske sivasspor og kroatiske dinamo zagreb samt uafgjort mod astana og cluj, men også en stribe nederlag og eliminering inden knockoutfasen.': 3,\n",
+ " 'vinder fcm dobbeltopgøret i anden runde, venter yderligere to runder, inden midtjyderne i så fald sikrer sig avancement til det meget lukrative gruppespil i champions league.': 3,\n",
+ " 'taber fcm i champions league-kvalifikations anden eller tredje runde, får holdet en ny chance i europa league-kvalifikationen, ligesom der også venter en tredje chance i conference league, hvis det også her kikser.': 3,\n",
+ " 'silkeborg deltog i lodtrækningen som useedet, hvorfor listen af mulige modstandere var af en vis kaliber.': 3,\n",
+ " 'også ajax, trabzonspor, cercle brugge og rapid wien var muligheder.': 3,\n",
+ " 'bag orkestret står james price.': 3,\n",
+ " '/ritzau/reuters': 3,\n",
+ " 'hoe kan dat?': 3,\n",
+ " 'nation’s white liberals announce they have successfully completed listening': 3,\n",
+ " '17 hours ago': 3,\n",
+ " 'promo sur la jbl xtreme 3': 3,\n",
+ " '-50% sur les focal aria 936 k2': 3,\n",
+ " '-600 euros sur la cabasse mc40 java': 3,\n",
+ " 'promo sur le dreame l10s pro ultra heat': 3,\n",
+ " 'promotion sur le ninja woodfire pro xl': 3,\n",
+ " '-2000 euros sur panasonic tx-65mz2000e': 3,\n",
+ " 'championnat de france': 3,\n",
+ " 'también puedes seguirnos en youtube, instagram, tiktok, x, facebook y en nuestro nuevo canal de whatsapp, donde encontrarás noticias de última hora y nuestro mejor contenido.': 3,\n",
+ " 'det meddeler tivoli torsdag til ritzau i en skriftlig kommentar.': 3,\n",
+ " 'det er ikke oplyst, hvad skuespilleren fejler, eller hvornår hun vender tilbage.': 3,\n",
+ " 'søndag blev to forestillinger ifølge tv 2 kosmopol aflyst grundet sygdom, men det blev ikke oplyst, hvem der var syg.': 3,\n",
+ " 'onsdagens forestilling blev ifølge mediet ligeledes aflyst.': 3,\n",
+ " 'skuespilleren afløses midlertidigt af komikeren lone rødbroe.': 3,\n",
+ " 'fra 1985 til 2022 var hun instruktør og kunstnerisk leder i cirkusrevyen.': 3,\n",
+ " 'kort før premieren på sin sidste sæson af cirkusrevyen i maj 2022 blev dahl ligeledes ramt af sygdom og måtte sygemeldes.': 3,\n",
+ " 'det skyldes dengang følgerne efter coronavirus, oplyste cirkusrevyen i en pressemeddelelse.': 3,\n",
+ " 'ud over dahls afløser består tivolirevyen af thomas eje, rikke buch bendtsen, rikke bilde, mikkel becker hilgart og james price.': 3,\n",
+ " 'det var ikke nok at inddrage': 3,\n",
+ " 'da slåskampen brød': 3,\n",
+ " 'ud, stod det klart, at man ikke': 3,\n",
+ " 'kan stoppe de britiske hooligans': 3,\n",
+ " 'jonas vingegaard udtaget': 3,\n",
+ " 'til tour de france': 3,\n",
+ " 'russisk krigsmaskine': 3,\n",
+ " 'internettet glemmer aldrig.': 3,\n",
+ " 'det ville jeg ønske, jeg havde forstået som 13-årig': 3,\n",
+ " 'kæmpe overraskelse: stor': 3,\n",
+ " 'centralbank sætter renten': 3,\n",
+ " 'ned for anden gang': 3,\n",
+ " 'lars løkke hæver stemmen:': 3,\n",
+ " '»jeg bliver så træt af det her«': 3,\n",
+ " 'formanden for': 3,\n",
+ " 'den tiltalte i korsør-sagen er ikke sindssyg – det er meget, meget værre': 3,\n",
+ " 'nogle trives alene, andre gør ikke.': 3,\n",
+ " 'folketingsmedlemmer: husk': 3,\n",
+ " 'din præst, når du har ondt i livet': 3,\n",
+ " 'denne serie er som et spark i maven - men du skal se den alligevel': 3,\n",
+ " 'onsdag aften blev stor politisk': 3,\n",
+ " 'alliance efterladt på perronen:': 3,\n",
+ " '»lidt for klogt af regeringen«': 3,\n",
+ " 'vi halter efter nabolande:': 3,\n",
+ " '»udefra ser det ud som en': 3,\n",
+ " 'tragedie i slowmotion«': 3,\n",
+ " 'medie: advokat fra tv-dokumentar lagt i økonomisk benlås af retten': 3,\n",
+ " 'sjælden harry potter-førsteudgave solgt på auktion': 3,\n",
+ " 'han var med til at forhandle den': 3,\n",
+ " 'første fred med putin.': 3,\n",
+ " 'han os om at huske bare én ting': 3,\n",
+ " 'profileret finansmand': 3,\n",
+ " 'hizbollah: »intet område« i': 3,\n",
+ " 'israel bliver »skånet for vores': 3,\n",
+ " 'raketter«, hvis der kommer krig': 3,\n",
+ " 'fejl på elnettet slukker': 3,\n",
+ " 'strømmen i hele ecuador': 3,\n",
+ " 'kun et land kan stoppe dem': 3,\n",
+ " 'læs også:\\xa0her kan kunstig intelligens påvirke flest job, mener amerikansk storbank': 3,\n",
+ " 'udvidelsen af havnen har været mange år undervejs, men blev i slutningen af maj stoppet af planklagenævnet.': 2,\n",
+ " 'den afgørelse er endelig og kan ikke indbringes for en anden administrativ myndighed.': 2,\n",
+ " 'efterfølgende lød det fra forligspartierne i aarhus byråd, at en ekstern undersøgelse skulle afdække, hvad der var gået galt i kommunens arbejde med udvidelsen.': 2,\n",
+ " 'her lød det, at kommunen stadig havde planer om en udvidelse af havnen, og derfor skulle lokalplanen genbesøges.': 2,\n",
+ " 'i perioden 2021 til 2023 har arbejdstilsynet 57 gange uddelt påbud til 46 grundskoler om at gribe ind over for et arbejdsmiljø med blandt andet vold og chikane mod lærere og pædagoger.': 2,\n",
+ " 'når arbejdstilsynet udsteder et påbud, betyder det, at der er sket en overtrædelse af arbejdsmiljøloven, og at arbejdsgiveren skal finde en løsning på problemet.': 2,\n",
+ " 'ifølge undervisningsministeriet var der i 2022 1066 folkeskoler i danmark.': 2,\n",
+ " 'i 55 ud af de 57 påbud fandt arbejdstilsynet, at der var problemer med fysisk vold mod personalet.': 2,\n",
+ " 'i 41 af tilfældene fandt tilsynet problemer med psykisk vold.': 2,\n",
+ " 'gennemgangen af rapporterne viser ifølge folkeskolen og gravercentret, at episoder med chikane eller fysiske overgreb finder sted ugentligt eller dagligt.': 2,\n",
+ " 'formand for danmarks lærerforening gordon ørskov madsen mener, at problemet er langt større end de 57 påbud.': 2,\n",
+ " '»det er helt givet.': 2,\n",
+ " 'det er det, vi hører, når vi spørger lærerne og børnehaveklasselederne.': 2,\n",
+ " 'det er langt fra første gang, at der rapporteres om problemer med vold mod lærere på landets folkeskoler.': 2,\n",
+ " 'i 2016 udstedte arbejdstilsynet 45 påbud for vold mod lærere.': 2,\n",
+ " 'i 2018 og 2019 viste en undersøgelse, at 45 procent af lærere og pædagoger i løbet af et år havde været udsat for fysisk vold.': 2,\n",
+ " 'der er desuden set eksempler på vold og grænseoverskridende adfærd mellem børn.': 2,\n",
+ " 'blandt de mest kendte er sagen fra borup skole på sjælland.': 2,\n",
+ " 'internationalt\\n \\n 18. jun.': 2,\n",
+ " 'pilgrimsfærden hajj finder sted hvert år i den islamiske kalenders sidste måned.': 2,\n",
+ " 'i år falder dette tidspunkt i midten af juni.': 2,\n",
+ " 'hajj er en af de fem søjler i islam og defineres ifølge islamisk ret som en religiøs pligt for alle muslimer, der har mulighed for at drage afsted til mekka.': 2,\n",
+ " 'le décret applique une disposition de la loi de financement de la sécurité sociale 2024.': 2,\n",
+ " 'les infirmières de pratique avancée (ipa) attendent le décret qui va permettre aux patients de prendre rendez-vous directement avec elles, sans ordonnance médicale.': 2,\n",
+ " 'ils attendent aussi un décret leur permettant de prescrire certains produits de santé, dont certains antalgiques et anti-inflammatoires.': 2,\n",
+ " 'publié le 19 juin 2024 à 07h42': 2,\n",
+ " 'championnats de france': 2,\n",
+ " 'on peut mieux faire.': 2,\n",
+ " \"(a.\\xa0martin/l'équipe)\": 2,\n",
+ " 'publié le 18 juin 2024 à 19h11': 2,\n",
+ " '1jour1actu a aimé\\xa0:': 2,\n",
+ " 'les informations de la nuit qu’il ne fallait pas manquer.': 2,\n",
+ " 'par\\n paul conge': 2,\n",
+ " 'par\\n jeanne auberger': 2,\n",
+ " 'elle est dans le collimateur du gouvernement depuis le début des émeutes, les autorités accusant ses responsables d’être les commanditaires des violences.': 2,\n",
+ " 'le barrage installé dans la rue par les militants a été déblayé.': 2,\n",
+ " 'les propos du président sur le changement de genre officiel sont indignes.': 2,\n",
+ " 'cette possibilité existe déjà dans la loi.': 2,\n",
+ " 'le président ignore la dose de souffrances que cela implique pour les personnes concernées.': 2,\n",
+ " \"d'autres pays ont compris qu'il faut laisser les gens se mettre…\": 2,\n",
+ " 'il estime que le président \"ignore la dose de souffrances que cela implique pour les personnes concernées\".': 2,\n",
+ " 'pour l’insoumis françois ruffin, emmanuel macron \"a choisi son camp, pour lui mieux vaut le national autoritaire que le front populaire\".': 2,\n",
+ " 'en marge d’un déplacement dans la marne, mardi, l’ex-premier ministre edouard philippe a déclaré porter \"un regard dubitatif sur ceux qui clament qu’ils sont prêts\" à occuper matignon \"alors qu’ils n’ont jamais rien géré\".': 2,\n",
+ " 'il a ainsi cité le président du rassemblement national, jordan bardella, promis à matignon en cas de succès de son parti.': 2,\n",
+ " '\"je sais que c’est dur, premier ministre.': 2,\n",
+ " '\"c’est difficile de gérer une commune, tous les maires vous le diront.': 2,\n",
+ " 'et c’est plus difficile de gérer l’etat\", a conclu edouard philippe.': 2,\n",
+ " 'la ministre des sports amélie oudéa-castéra s’est indignée mardi des propos de l’ancien champion olympique guy drut.': 2,\n",
+ " 'dans un entretien paru le même jour dans le monde, celui-ci s’est prononcé pour une alliance entre les républicains (lr), parti dont il est issu, et le rassemblement national (rn).': 2,\n",
+ " '\"je reste et je voterai les républicains, tendance éric ciotti, parce que j’approuve l’union des droites et l’alliance avec le rassemblement national (rn)\", a déclaré guy drut, ancien ministre des sports sous le gouvernement d’alain juppé (1995-1997).': 2,\n",
+ " 'si nous donnions de l’eau potable aux comores et à mayotte, nous n’entendrions définitivement plus parler de choléra autochtone là-bas.': 2,\n",
+ " 'selon la professeure émérite de droit public martine lombard, de nombreuses difficultés se dressent sur la route du rn avant de parvenir à privatiser le service public audiovisuel.': 2,\n",
+ " '17-06-2024 à 11:46': 2,\n",
+ " 'vous n’avez plus voté depuis dix, vingt ans ou plus mais vous avez décidé de rompre avec cette tradition pour les législatives\\xa0?': 2,\n",
+ " 'kein land der welt dürfe russlands aggression unterstützen.': 2,\n",
+ " 'berlin, berlin – wer fährt nach berlin?': 2,\n",
+ " 'juni bis zum 14.': 2,\n",
+ " 'juli ist deutschland gastgeber der fußball-europameisterschaft.': 2,\n",
+ " '24 mannschaften kämpfen um den titel, die erwartungen an das team von julian nagelsmann sind groß.': 2,\n",
+ " 'das finale findet im berliner olympiastadion statt.': 2,\n",
+ " 'hier finden sie news, reportagen, interviews und analysen.': 2,\n",
+ " 'seit mehr als zwei jahren führt russland einen angriffskrieg gegen das nachbarland ukraine.': 2,\n",
+ " 'die ukraine hat immer wieder angekündigt, die krim von der russischen besatzung zu befreien.': 2,\n",
+ " 'bei der em-übertragung war eine europa-karte vor dem tisch von moderator kerner und experte michael ballack eingeblendet worden, die alle teilnehmer-länder der europameisterschaft in deutschland zeigte.': 2,\n",
+ " 'dabei waren die länder mit ihren jeweiligen flaggen farblich hervorgehoben.': 2,\n",
+ " 'bei der ukraine war jedoch die krim nicht in den ukrainischen farben eingefärbt.': 2,\n",
+ " 'in sozialen medien machten mehrere nutzer auf den fehler aufmerksam und posteten screenshots.': 2,\n",
+ " '„heute ist ein neues grundlagendokument fertig, das die basis für unsere langfristigen beziehungen legen wird“, sagte putin laut russischen nachrichtenagenturen am mittwoch in der nordkoreanischen hauptstadt.': 2,\n",
+ " 'moskau und pjöngjang seien bei der stärkung ihrer bilateralen beziehungen „weit vorangekommen“.': 2,\n",
+ " 'sie sagte, die lieferung von waffen aus nordkorea hätte dazu beigetragen, dass russland in der lage sei, seinen brutalen krieg in der ukraine zu führen.': 2,\n",
+ " 'diese staaten unterstützten russlands kriegsaggression gegen die ukraine und heizten diese an.': 2,\n",
+ " '„das zeigt auch, dass unsere sicherheit nicht regional ist.': 2,\n",
+ " 'man sei auch besorgt darüber, dass russland technologie für die raketen- und atomprogramme dieser länder bereitstelle.': 2,\n",
+ " 'auch deshalb werde man beim nato-gipfel in washington im juli die zusammenarbeit mit partnern im indopazifik-raum weiter stärken, betonte stoltenberg.': 2,\n",
+ " '„das klappt.': 2,\n",
+ " 'genauso wie wir es erwartet haben.“ der ukrainische staatschef lobte dabei mehrere einheiten für nicht näher benannte erfolge.': 2,\n",
+ " 'westliche staaten hatten nach neuen russischen angriffen gegen das gebiet charkiw im nordosten der ukraine ihr verbot zum einsatz ihrer waffen gegen russisches staatsgebiet gelockert.': 2,\n",
+ " 'es sei den ukrainern gelungen, die russischen offensiven abzubremsen.': 2,\n",
+ " 'tatsächlich sind die geländegewinne der russischen truppen in den vergangenen wochen immer geringer geworden, was beobachter auch darauf zurückführen, dass nun westliche waffen nach längerer pause wieder bei den ukrainischen verteidigern ankommen.': 2,\n",
+ " 'carlota brandis': 2,\n",
+ " 'in der em-prognose der f.a.z.': 2,\n",
+ " 'von daniel memmert und fabian wunderlich zeigt sich in vier verschiedenen kategorien, wer die besten chancen hat.': 2,\n",
+ " 'die siegwahrscheinlichkeit basiert auf daten des wettmarkts.': 2,\n",
+ " 'daniel memmert, mathematiker, professor und geschäftsführender institutsleiter am institut für trainingswissenschaft und sportinformatik, kennt insbesondere auch die psychologischen tücken von vorhersagen und konnte in eigener forschung belegen, dass sich experten dabei regelmäßig überschätzen.': 2,\n",
+ " 'daher empfiehlt er statt auf einzelne expertenmeinungen lieber auf die prognosen von datenbasierten modellen zu vertrauen.': 2,\n",
+ " 'seine weiteren arbeitsschwerpunkte liegen in der bewegungswissenschaft (kognition und motorik), in der sportpsychologie (aufmerksamkeit und motivation) sowie in der sportinformatik (big data, ml, ki).': 2,\n",
+ " 'sein institut kooperiert mit verschiedenen fußball-bundesligavereinen, dax-unternehmen und organisiert den ersten internationalen weiterbildungs-masterstudiengang „spielanalyse“ sowie das zertifikat „sportdirektor im amateur- und nachwuchsleistungsfußball“.': 2,\n",
+ " 'fabian wunderlich, mathematiker, hat mehrere jahre im sportwetten-bereich gearbeitet und an der deutschen sporthochschule köln zum thema vorhersagemodelle im sport promoviert.': 2,\n",
+ " 'seine primäre expertise liegt in der anwendung von mathematischen und informatischen verfahren auf sportdaten und seine forschungsschwerpunkte unter anderem in den bereichen vorhersagemodelle, sportwetten, wettquoten sowie zufallseinflüsse im sportspiel.': 2,\n",
+ " 'gemeinsam haben sich beide in einem übersichtsartikel mit vorhersagemodellen im sport befasst und in einer aktuellen studie den hohen zufallseinfluss im fußball nachgewiesen, der letztendlich die vorhersagen so schwierig macht.': 2,\n",
+ " 'darüber hinaus wissen sie, wie wichtig wettquoten im vorhersagebereich sind, und haben den nutzen von wettquoten für die analyse von leistungsstärken und in der vorhersage von fußballspielen untersucht.': 2,\n",
+ " 'weitere aktuelle studien befassen sich mit der frage, inwiefern positionsdaten oder social-media-daten vorhersagemodelle für fußballspiele verbessern können.': 2,\n",
+ " 'während sich viele sportfans am mittwoch das zweite vorrundenspiel der dfb-elf gegen ungarn ansehen werden, muss alexander zverev auf den tennisplatz.': 2,\n",
+ " 'zur allgemeinen verwunderung setzten die veranstalter des turniers im westfälischen halle das achtelfinale des tennis-olympiasiegers gegen den italiener lorenzo sonego parallel zum zweiten auftritt der nationalelf an.': 2,\n",
+ " '„das war definitiv nicht mein wunsch“, sagte zverev am dienstagabend nach seinem erstrunden-sieg gegen oscar otte.': 2,\n",
+ " '„aber ich bestimme es nicht.': 2,\n",
+ " 'wenn ich es bestimmen würde, würde ich es anders machen.': 2,\n",
+ " 'ich glaube, es war um ehrlich zu sein nicht schlau vom turnier“, sagte der weltranglistenvierte, der selbst großer fußball-fan ist.': 2,\n",
+ " '„wenn ich nicht spielen würde, würde ich mir auch kein tennis-match anschauen, sondern würde fußball gucken.“': 2,\n",
+ " 'die veranstalter wollten sich zunächst nicht zu dem ungewöhnlichen spielplan äußern.': 2,\n",
+ " 'das zverev-match ist die vierte begegnung des tages in der owl arena.': 2,\n",
+ " 'zuvor spielen unter anderem jan-lennard struff, dominik koepfer und der russe daniil medwedew.': 2,\n",
+ " 'erst danach ist zverev an der reihe.': 2,\n",
+ " 'kurios: die organisatoren werben damit, dass von 18.00 uhr an hinter der arena ein public viewing zu deutschland gegen ungarn stattfinden sol.': 2,\n",
+ " 'genau zu dem zeitpunkt, wenn in zverev das zugpferd der veranstaltung im einsatz ist.': 2,\n",
+ " 'by adam douglas thompson': 2,\n",
+ " '8 hours ago': 2,\n",
+ " '“i flew from england to washington dc to hear in person what the boeing ceo has to say to the senate and to the world about any safety improvements made at that corporation,” said zipporah kuria, whose father was killed in the 2019 crash of a boeing 737 max 8 jet.': 2,\n",
+ " '“i also continue to press the us government to hold boeing and its corporate executives criminally responsible for the deaths of 346 people.': 2,\n",
+ " 'we will not rest until we see justice.”': 2,\n",
+ " 'by\\xa0alex mcintyre,\\xa0bbc news, west midlands': 2,\n",
+ " '2 hours ago': 2,\n",
+ " \"if you would like to hear more about election issues in wales and get the chance to have your say you can sign up to the bbc's live audience programmes here.\": 2,\n",
+ " '13 hours ago': 2,\n",
+ " 'at the economist we are best known for producing a weekly newspaper, but we also publish an annual every november, looking forward to the year ahead.': 2,\n",
+ " 'the latest edition, “the world in 2020” has just appeared.': 2,\n",
+ " 'it features analysis and forecasts from our journalists (unusually, this is one occasion on which we get bylines), our colleagues at the economist intelligence unit (who provide pithy summaries of the outlook for dozens of countries and industries) and a distinguished group of external contributors.': 2,\n",
+ " 'this year this final group included demis hassabis, co-founder of deepmind; jacinda ardern, prime minister of new zealand; ren zhengfei, founder of huawei; and robert f. smith, a private-equity billionaire who, while giving a commencement address in may at morehouse college, told the class of 2019 that he would pay off their student loans when they graduate.': 2,\n",
+ " 'our aim with this annual, of which i am the deputy editor, is not so much to make precise predictions about the coming year as to give readers a wide range of stimulating ideas and perspectives to help them navigate it.': 2,\n",
+ " 'but all our contributors have one thing in common: they are human.': 2,\n",
+ " 'so for this year’s edition, i thought it might be fun to ask an artificial intelligence (ai) about the future.': 2,\n",
+ " 'i have been tinkering with chatbots and text-generating algorithms since i was a teenager, and i went to university to study ai in the late 1980s—only to discover, alas, that ai didn’t really work.': 2,\n",
+ " 'but in recent years a specific technique called deep learning has led to extraordinary progress in the field.': 2,\n",
+ " 'most of what is called ai today, from facial recognition to voice assistants to machine translation, is in fact deep learning if you look under the hood.': 2,\n",
+ " 'and in february 2019 openai, a research outfit based in san francisco, unveiled a “large-scale unsupervised language model” called gpt-2 that was created by applying a flavour of deep learning, called unsupervised learning, to 40 gigabytes of text extracted from 8m web pages on a wide range of topics.': 2,\n",
+ " 'the resulting system is uncannily good at generating text in a specific style: you give it a few words as a prompt, and it then guesses what comes next, based on patterns in the text it was trained on, like a sort of supercharged autocomplete, powered by gigabytes of past examples.': 2,\n",
+ " 'openai’s announcement included examples of gpt-2 writing tolkienesque fantasy fiction and (fictitious) news-agency stories about unicorns and stolen nuclear material, complete with quotes from (entirely made-up) sources.': 2,\n",
+ " 'it also turned out to be surprisingly good at comprehension, summarisation and other language tasks, despite not having been designed to do those things.': 2,\n",
+ " 'citing the risk that this program might be misused by propagandists to generate “fake news” stories, openai decided not to release the full version of gpt-2 right away; instead, it was released in stages, starting with an initial, watered-down version, and slowly working up to the full-strength version over several months.': 2,\n",
+ " 'this was something of a publicity stunt, and resulted in many headlines along the lines of “ai lab decides its creation is too dangerous to make public”.': 2,\n",
+ " 'but it was also a way for openai to emphasise the point that it takes the misuse of technology seriously (its mission is “to ensure that artificial general intelligence benefits all of humanity”), with the strong implication that others in the tech industry ought to do the same.': 2,\n",
+ " 'when i saw gpt-2’s results, though, its propaganda potential was not what most interested me.': 2,\n",
+ " 'instead i began to wonder how i could use it as a chatbot, like the ones i used to play with in the 1980s.': 2,\n",
+ " '(the most famous example from the early personal-computer era is eliza, but my favourite was racter, a text-generation system that wrote a book called “the policeman’s beard is half-constructed”.)': 2,\n",
+ " 'helpfully for me, the gpt-2 code is available on github; even more helpfully, it can be accessed via a jupyter notebook created by ignacio lópez-francos, a researcher at nasa.': 2,\n",
+ " 'this spins up a powerful computer at google, loads the gpt-2 model onto it, and then lets anyone play with it via a web browser.': 2,\n",
+ " 'with a bit of fiddling i figured how i could use it to do an “interview” with gpt-2.': 2,\n",
+ " 'i thought it would be amusing to get a deep-learning system to generate answers to questions about the impact of ai on society in the coming decades, a subject of endless speculation and debate.': 2,\n",
+ " 'human experts cannot agree on whether robots and ai will lead to mass unemployment or not, for example.': 2,\n",
+ " 'might a machine produce a more coherent answer?': 2,\n",
+ " 'probably not, but it would be an interesting experiment.': 2,\n",
+ " 'of course, gpt-2 cannot really predict the future.': 2,\n",
+ " 'for a start, it doesn’t actually understand anything: it just sometimes appears to, because it is very good at generating text in particular styles, by regurgitating words and phrases it has heard before in the same kind of context in response to a prompt.': 2,\n",
+ " 'and the reams of text it was trained on were gathered in late 2017, and are thus rather out of date.': 2,\n",
+ " 'as a predictive tool, then, gpt-2 is no better than a magic 8-ball.': 2,\n",
+ " 'but i was curious about how plausible its answers might be.': 2,\n",
+ " 'it turns out that simply feeding it questions as prompts does not produce very relevant answers; instead, it helps to give it a clearer idea of context.': 2,\n",
+ " 'so i wrote an introductory paragraph, setting the scene and indicating to gpt-2 the style, tone and subject-matter of the text i wanted it to generate.': 2,\n",
+ " 'i then added a question, prefixed with “q:”, and began the next line with “a:” to indicate that the next words should be the answer.': 2,\n",
+ " '(gpt-2’s training set includes many q&as, so it recognises the format.': 2,\n",
+ " 'similarly, it can be prompted to generate numbered lists, or recipes, which also appear in its training data.)': 2,\n",
+ " 'the first prompt i used was:': 2,\n",
+ " 'i configured gpt-2 to generate five responses to each question and set the maximum output length to 75 words.': 2,\n",
+ " '(i did all this in september, so i used the 774m version of the gpt-2 model; the full-strength version had not been released at the time, though it since has been.)': 2,\n",
+ " 'here is a typical answer:': 2,\n",
+ " 'in this case gpt-2 has provided an answer to my original question, and has then generated subsequent questions and answers.': 2,\n",
+ " 'the “gartner symposium on data-driven technologies” is an entirely made-up event, but is a surprisingly plausible invention (the gartner data analytics summit, by contrast, does really exist).': 2,\n",
+ " 'here is another response to the same question, which starts with a much less interesting answer (and also includes follow-on questions and answers generated by gpt-2):': 2,\n",
+ " 'and here’s another one:': 2,\n",
+ " 'in this case, the follow-on questions and answers show that gpt-2 is generating text in the right subject area, namely the relationship between people and machines.': 2,\n",
+ " 'but that wasn’t part of the answer to my initial question.': 2,\n",
+ " 'so to generate my “interview”, i selected the most coherent, interesting or amusing of the five responses in each case, chopping off any follow-on questions and answers at the end.': 2,\n",
+ " 'i then added the resulting answer, and my next question, to the end of the prompt, and fed it back into gpt-2.': 2,\n",
+ " 'taking the first example above, that would mean extending the prompt as follows:': 2,\n",
+ " 'repeatedly extending the prompt in this way ensured that the questions and answers took place in the same context.': 2,\n",
+ " 'in fact, there is a limit to the size of the input prompt, so after several questions i had to remove the initial paragraph from the prompt, and just feed in the preceding set of question and answer pairs.': 2,\n",
+ " 'here is the resulting article, which was published in “the world in 2020”.': 2,\n",
+ " 'it includes the following exchange about the risks of ai:': 2,\n",
+ " 'q: how worried do you think we humans should be that \\xadmachines will take our jobs?a: it depends what role machine intelligence will play.': 2,\n",
+ " 'machine intelligence in some cases will be useful for solving problems, such as translation.': 2,\n",
+ " 'but in other cases, such as in finance or medicine, it will replace people.': 2,\n",
+ " 'q: do fake news stories, generated using ai, pose a threat to democracy?': 2,\n",
+ " 'are we likely to see this tactic being used in the 2020 american presidential elections?a: yes, we’ll probably see them.': 2,\n",
+ " 'it’s just a matter of when.': 2,\n",
+ " 'fake news stories are generally generated by political campaigns, and have the potential to have a huge impact on the outcome of an election.': 2,\n",
+ " 'this is because they spread misinformation, often with no basis in fact.': 2,\n",
+ " 'some people on twitter have challenged my use of the word “unedited” to describe these answers.': 2,\n",
+ " 'they have a point.': 2,\n",
+ " 'as explained above, i selected an answer from the five responses generated in each case (and did not keep the discarded responses, a decision i now regret).': 2,\n",
+ " 'i also lopped off any follow-on questions and answers.': 2,\n",
+ " 'i did not tinker with the text of the resulting answer; each of the answers in the piece really was generated in that form by gpt-2.': 2,\n",
+ " 'but calling them “unedited” was, in hindsight, something of a stretch.': 2,\n",
+ " 'several people also asked for more detail about how i conducted the interview, given that there was not room to explain it in the original article (the length of which was limited to a single printed page).': 2,\n",
+ " 'that’s why i’ve written this post.': 2,\n",
+ " 'if you want to give gpt-2 a quick try, though, there are easier ways to do it, though they allow less control: talktotransformer.com, another web-based interface to gpt-2 (which is named after the program’s so-called transformer-based architecture), makes it as easy as using a search engine.': 2,\n",
+ " 'mine is just one contribution to a burgeoning field: the new yorker used a specially tuned version of gpt-2 to generate paragraphs in the middle of an article by john seabrook, and the new york times used it, and a similar text-generation system developed by the allen institute, to create paragraphs of “fake news”, challenging readers to distinguish between human- and computer-generated disinformation.': 2,\n",
+ " 'gpt-2 has also been used to generate recipes, fan fiction and poetry (see janelle shane’s hilarious website, aiweirdness, for some of the funniest examples).': 2,\n",
+ " 'in nearly all of these cases human selection has played a role, picking out the most interesting examples from its output.': 2,\n",
+ " 'does that give a misleading impression of what gpt-2 and similar systems are capable of?': 2,\n",
+ " 'one of the great things about this technology is that, simply by playing around with gpt-2 in a web browser, you can decide the answer to that question for yourself.': 2,\n",
+ " 'tom standage is deputy editor of the economist and of “the world in 2020”.': 2,\n",
+ " 'premium11:45binnenland': 2,\n",
+ " 'premium10:52buitenland': 2,\n",
+ " 'premium10:00buitenland': 2,\n",
+ " 'premium08:21binnenland': 2,\n",
+ " 'premium18 jun.cultuur': 2,\n",
+ " '18 jun.financieel': 2,\n",
+ " '©\\xa0getty images': 2,\n",
+ " 'premium17 jun.sterren': 2,\n",
+ " \"foto's familie tantesh\": 2,\n",
+ " '26 mei 2023': 2,\n",
+ " 'oranje heeft sinds dit ek eindelijk weer een vaste doelman.': 2,\n",
+ " 'de opvoedvraag': 2,\n",
+ " 'een 11-jarig meisje werkt aan een glorieuze toekomst als jonge internetondernemer.': 2,\n",
+ " 'maar wat als ze daardoor in financiële problemen komt?': 2,\n",
+ " 'meiden die armbandjes maken of jongens die snoep importeren uit de vs en dit aanprijzen via tiktok of instagram.': 2,\n",
+ " 'nog nooit was het als jongere zo makkelijk om een eigen bedrijfje te beginnen.': 2,\n",
+ " '“onze dochter maakt zelf armbandjes en koopt haarspelden die ze met winst doorverkoopt.': 2,\n",
+ " 'we vinden haar ondernemingszin leuk om te zien.': 2,\n",
+ " 'maar we hebben zelf weinig verstand van ondernemen en weten niet zo goed waar we op moeten letten”, zeggen haar ouders.': 2,\n",
+ " '“we zouden het vreselijk vinden als ze door haar enthousiasme in de problemen komt.”': 2,\n",
+ " '“laat haar lekker uitproberen.': 2,\n",
+ " 'ondernemen is leuk, ze kan er veel van leren en misschien verdient ze er ook nog wat geld mee”, zegt kim meijer van geldboompje en auteur van van jouw idee naar eigen baas.': 2,\n",
+ " 'hierin geeft zij jongeren tips en advies om hun beginnende ondernemersdroom waar te maken.': 2,\n",
+ " 'het meisje is met 11 jaar wat aan de jonge kant, maar dat is geen reden om haar te ontmoedigen.': 2,\n",
+ " 'er zijn zelfs kinderen van 9 of 10 jaar die al een eigen bedrijfje starten.': 2,\n",
+ " 'er zijn steeds meer minderjarige ondernemers, weet gerdine annaars, adviseur bij de kamer van koophandel en gespecialiseerd in jonge ondernemers.': 2,\n",
+ " 'op 1 januari 2018 stonden er in het kvk-handelsregister nog 792 ondernemers van twaalf tot en met zeventien jaar ingeschreven.': 2,\n",
+ " 'op 1 januari 2024 waren dat er al 3250.': 2,\n",
+ " 'en dat zijn alleen de jongeren die zich officieel hebben aangemeld.': 2,\n",
+ " '“er zijn ook kinderen en jongeren die ondernemen, maar zich niet hebben ingeschreven”, zegt annaars.': 2,\n",
+ " '“dat is namelijk niet altijd verplicht.”': 2,\n",
+ " 'qua papierwinkel hoeft er aanvankelijk niet zo veel geregeld te worden.': 2,\n",
+ " 'de kamer van koophandel geeft uitleg op de site, speciaal voor ouders.': 2,\n",
+ " 'annaars: “zolang je op kleine schaal producten of diensten aanbiedt, is het vooral een leuke bijverdienste of hobby.': 2,\n",
+ " 'pas als je meer geld investeert, een wat grotere omzet hebt, actief klanten werft en reclame maakt en veel tijd aan je bedrijf besteedt, moet je je inschrijven bij de kvk.': 2,\n",
+ " 'voor veel kinderen geldt dat niet direct.': 2,\n",
+ " 'wel kan het zo zijn dat je belasting moet betalen over je inkomsten.': 2,\n",
+ " 'het is dus altijd slim om een overzicht te hebben over je kosten, opbrengsten en uren die je eraan besteedt.': 2,\n",
+ " 'hier kunnen ouders hun kind zeker bij helpen.”': 2,\n",
+ " 'geld verdienen is leuk, maar zou niet het hoofddoel moeten zijn.': 2,\n",
+ " 'meijer: “als je sommige influencers op sociale media ziet, denk je dat je er steenrijk van wordt.': 2,\n",
+ " 'maar dat is meestal niet zo.': 2,\n",
+ " 'het is goed om dat je kind voor te houden.': 2,\n",
+ " 'en het is goed om mee te geven dat hard werken niet altijd loont.': 2,\n",
+ " 'het kan misgaan.”': 2,\n",
+ " 'wat is mijn idee, wat zijn mijn doelen, wie of wat heb ik ervoor nodig?': 2,\n",
+ " '“je hoeft geen uitgebreid bedrijfsplan te hebben, maar je moet er wel over nagedacht hebben”, aldus meijer.': 2,\n",
+ " 'zo zal het meisje wat geld moeten investeren voordat ze iets kan verkopen.': 2,\n",
+ " '“denk bijvoorbeeld aan kraaltjes of verpakkingsmateriaal.': 2,\n",
+ " 'als je armbandjes maakt, kom je met 100 euro al een eind, maar het kan ook een stuk duurder uitpakken.': 2,\n",
+ " 'die kosten moet je meenemen in de prijs van je product.”': 2,\n",
+ " 'het ‘startkapitaal’ leent het meisje misschien van haar ouders of ze gebruikt er spaargeld voor.': 2,\n",
+ " 'meijer: “op deze manier leert ze wat het betekent om een lening te hebben en deze terug te moeten betalen.”': 2,\n",
+ " 'ondernemen heeft niet alleen maar leuke kanten, zoals filmpjes online zetten.': 2,\n",
+ " 'het kost best veel tijd, terwijl een kind ook gewoon naar school moet of wil sporten.': 2,\n",
+ " '“bewaak als ouder dus de tijd die je kind eraan kwijt is”, zegt annaars.': 2,\n",
+ " 'verder is het belangrijk om in de gaten te houden of er geen misbruik van het kind wordt gemaakt.': 2,\n",
+ " 'bijvoorbeeld door een klagende klant of iemand die niet wil betalen.': 2,\n",
+ " 'meijer: “tegelijkertijd: ook daar leer je van.': 2,\n",
+ " 'hoe kan ik het een volgende keer beter doen?': 2,\n",
+ " 'zorg er vooral voor dat je kind kan genieten van wat ze leert én wat ze ermee verdient.”': 2,\n",
+ " 'is het normaal dat onze zoon (13) alles drie keer checkt?': 2,\n",
+ " '‘onze zoon slaat in een boze bui mijn vrouw’': 2,\n",
+ " 'ons kleinkind daagt ons uit met storend, destructief gedrag': 2,\n",
+ " 'de goedkeuring van de hongaarse premier orbán maakt ruttes benoeming tot navo-baas zeker.': 2,\n",
+ " 'de twee premiers stonden zelfs glimlachend en handenschuddend op de foto.': 2,\n",
+ " 'maar dat kan niet.': 2,\n",
+ " 'woorden doen ertoe.': 2,\n",
+ " 'ga naar een specifiek onderdeel:': 2,\n",
+ " 'met succes.': 2,\n",
+ " 'traangas maakt ademhalen lastig.': 2,\n",
+ " 'het brandt op de huid.': 2,\n",
+ " 'de lucht is een ziekmaker.': 2,\n",
+ " 'hoe kan die schoner worden?': 2,\n",
+ " 'ik heb geen excuses nodig, van niemand.': 2,\n",
+ " 'nos nieuws•vandaag, 12:02': 2,\n",
+ " 'china is ontstemd over een bezoek dat amerikaanse politici vandaag hebben gebracht aan de dalai lama.': 2,\n",
+ " 'volgens peking geeft een audiëntie bij de leider van de tibetaanse boeddhisten \"de wereld het verkeerde signaal\".': 2,\n",
+ " 'een delegatie van zowel republikeinse als democratische congresleden zocht de 88-jarige spiritueel leider vandaag op in zijn hoofdkwartier in het indiase dharamshala, waar hij sinds 1959 woont nadat china tibet had geannexeerd.': 2,\n",
+ " 'het bezoek werd geleid door de republikeinse voorzitter van de buitenlandcommissie van het huis van afgevaardigden, michael mccaul.': 2,\n",
+ " 'ook de democratische oud-voorzitter van het huis nancy pelosi reisde mee.': 2,\n",
+ " 'de ontmoeting komt op een moment dat de vs en china meer toenadering zoeken na jaren van onderlinge wrevel over de economische betrekkingen, mensenrechten en de internationale verhoudingen.': 2,\n",
+ " \"tegelijkertijd zijn de twee grootmachten het nog altijd oneens over grote dossiers, zoals china's rugdekking van poetin, de status van taiwan en chinese expansie ten koste van andere landen in de regio.\": 2,\n",
+ " 'china had de delegatie vooraf gewaarschuwd weg te blijven.': 2,\n",
+ " '\"deze week nog kregen we een brief van de chinese communistische partij met een waarschuwing niet hier te komen\", vertelde mccaul het publiek na het bezoek.': 2,\n",
+ " '\"maar we laten ons niet intimideren, want hier zijn we.\"': 2,\n",
+ " 'de opmerking werd met gejuich ontvangen.': 2,\n",
+ " 'het bezoek stond in het teken van een oproep van het amerikaanse congres aan china om de dialoog met de dalai lama te hervatten.': 2,\n",
+ " 'het land heeft nooit de tibetaanse regering in ballingschap erkend en er is sinds 2010 geen onderling contact meer.': 2,\n",
+ " 'china ziet die oproepen als bemoeienis met de binnenlandse politiek.': 2,\n",
+ " 'het wijst erop dat tibet eeuwenlang onderdeel was van china en zegt dat de annexatie rust en vooruitgang heeft gebracht.': 2,\n",
+ " '\"iedereen weet dat de veertiende dalai lama niet alleen een religieus figuur is, maar als politiek banneling onder het mom van religie anti-chinese separatistische activiteiten ontplooit\", stelt een chinese regeringswoordvoerder, die de vs opriep al het contact met de tibetaanse leider te verbreken.': 2,\n",
+ " 'de dalai lama zelf ontkent uit te zijn op tibetaanse onafhankelijkheid en zegt alleen te pleiten voor meer autonomie en bescherming van geloofsgenoten.': 2,\n",
+ " 'china ligt al jaren onder vuur voor het onderdrukken van de tibetanen; critici wijzen erop dat de vrijheid van meningsuiting beperkt is en dat tibetanen hun cultuur en geloof niet vrijuit kunnen uiten.': 2,\n",
+ " 'het land is al jaren zo goed als ontoegankelijk voor buitenstaanders.': 2,\n",
+ " 'china waarschuwt het witte huis de congresverklaring niet officieel te bekrachtigen, omdat er dan \"krachtdadige maatregelen\" zullen volgen.': 2,\n",
+ " 'de woordvoerder ging niet in op wat dat precies zou betekenen.': 2,\n",
+ " 'in het verleden heeft china vaker geprikkeld gereageerd op amerikaanse delegaties in de regio.': 2,\n",
+ " 'zo leidde een bezoek van pelosi aan taiwan tot uitgebreide chinese militaire oefeningen rond het eiland.': 2,\n",
+ " 'een nieuw precair moment volgt mogelijk later deze week, als de dalai lama naar de vs reist voor een kniebehandeling.': 2,\n",
+ " 'het is nog niet bekend of hij dan verdere ontmoetingen zal hebben met amerikaanse afgevaardigden.': 2,\n",
+ " 'in het verleden had de dalai lama ontmoetingen met alle amerikaanse presidenten, op donald trump na.': 2,\n",
+ " 'ook president biden heeft hij tot nu toe nog niet ontmoet.': 2,\n",
+ " 'nos nieuws•vandaag, 09:25': 2,\n",
+ " 'de fnp-fractie in de provincie wil instemmen met bezuinigingen van in totaal 800.000 euro, terwijl de tien fnp-wethouders van gemeenten in friesland fel tegen zijn.': 2,\n",
+ " '\"fries taalbeleid en cultuur de nek laten omdraaien door de fnp kan niet\", schrijft wethouder jan dijkstra (fnp) van de gemeente waadhoeke in een brief aan de statenfractie die is ingezien door omrop fryslân.': 2,\n",
+ " 'de bezuinigingen zitten al een tijdje in de pen en leidden begin juni nog tot een protestmanifestatie van cultuurorganisaties.': 2,\n",
+ " '\"ik vind de bezuinigingen niet nodig en onacceptabel\", zei directeur douwe zeldenrust van keunstwurk toen.': 2,\n",
+ " 'keunstwurk houdt zich bezig met talentontwikkeling bij jongeren, amateurkunst en cultuureducatie.': 2,\n",
+ " '\"zo maak je een boel dingen kapot die je juist nodig hebt na corona\", aldus zeldenrust.': 2,\n",
+ " 'ook de vereniging van friese gemeenten (vfg) heeft zorgen over de voorgestelde bezuinigingen.': 2,\n",
+ " 'maar de fnp in de provincie is toch van plan om in te stemmen.': 2,\n",
+ " '\"het is nu feitelijk voor het eerst dat de provincie fryslân echt moet bezuinigen.': 2,\n",
+ " 'dat is ook verantwoordelijkheid nemen en besturen.': 2,\n",
+ " 'besturen is niet altijd eenvoudig\", laat de fnp-statenfractie weten.': 2,\n",
+ " '\"als wij tegen de bezuinigingen stemmen, dan breken we met ons akkoord met bbb, cda en christenunie en zijn wij niet consequent.': 2,\n",
+ " 'we moeten nu de pijn nemen, ook omdat we denken dat de keuzes acceptabel zijn.\"': 2,\n",
+ " 'de fnp-statenfractie wijst er ook op dat de provincie weliswaar wil bezuinigen op taal en cultuur, maar dat het rijk juist extra geld beschikbaar stelt voor friese projecten in het kader van de nieuwe bestjoersôfspraak fryske taal en kultuer (bftk), in totaal 18 miljoen euro.': 2,\n",
+ " 'maar met dat geld uit den haag zijn organisaties als keunstwurk nog niet gered, zeggen de tien kritische wethouders.': 2,\n",
+ " '\"met eenmalig geld kun je geen structurele zaken overeind houden\", stelt wethouder dijkstra.': 2,\n",
+ " '\"juist de ondersteuning van de provincie geeft gemeenten de kans om iets met het taalbeleid te doen.': 2,\n",
+ " 'ook gemeenten die er minder mee hebben.\"': 2,\n",
+ " 'dus roept dijkstra mede namens de andere negen fnp-wethouders de statenfractie op om tegen de bezuinigingen te stemmen.': 2,\n",
+ " 'de wethouders: \"naast dat het een slechte ontwikkeling is, hebben wij hier als partij veel last van.': 2,\n",
+ " 'ik denk dat er wel andere oplossingen zijn.': 2,\n",
+ " 'daar denken we ook graag over mee.\"': 2,\n",
+ " 'provinciale staten praten vandaag over de zogeheten taalnota fries.': 2,\n",
+ " 'onderdeel van die nota zijn de voorgenomen bezuinigingen.': 2,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von youtube, der den artikel ergänzt und von der redaktion empfohlen wird.': 2,\n",
+ " 'an dieser stelle finden sie einen externen inhalt von x.com, der den artikel ergänzt und von der redaktion empfohlen wird.': 2,\n",
+ " 'alexander bakker': 2,\n",
+ " 'lunch update': 2,\n",
+ " 'dagelijks tijdens de lunch een update van het belangrijkste nieuws.': 2,\n",
+ " 'fonctionnalités supplémentaires': 2,\n",
+ " 'die christdemokraten im europäischen parlament haben am mittwoch den csu-politiker manfred weber als vorsitzenden wiedergewählt.': 2,\n",
+ " 'weber bekam 95 prozent der stimmen, wie die fraktion der europäischen volkspartei (evp) mitteilte.': 2,\n",
+ " 'er hat das amt schon seit 2014 inne, seit 2022 ist er außerdem vorsitzender der parteienfamilie.': 2,\n",
+ " 'schon am vortag hatte die größte fraktion im neu gewählten europäischen parlament 14 abgeordnete aufgenommen, darunter sieben von der partei tisza aus ungarn.': 2,\n",
+ " 'deren vorsitzender péter magyar entschied sich entgegen früherer ankündigungen, sein mandat in straßburg anzunehmen.': 2,\n",
+ " 'er hat sich mit der europawahl als wichtigster konkurrent von regierungschef viktor orbán etabliert.': 2,\n",
+ " 'magyar begründete seinen schritt damit, dass 75 prozent der anhänger seiner neuen partei in einer online-abstimmung dafür votiert haben, dass er ins europäische parlament geht.': 2,\n",
+ " 'im ungarischen parlament wird er gleichwohl ein rederecht haben, sofern es dort um themen mit eu-bezug geht.': 2,\n",
+ " 'magyar, 43 jahre alt, war viele jahre mitglied von viktor orbáns partei fidesz, bevor er im märz der partei tisza beitrat.': 2,\n",
+ " 'als deren spitzenkandidat gewann er bei der europawahl fast 30 prozent der stimmen, während der fidesz auf 45 prozent kam.': 2,\n",
+ " 'nach der aufnahme in die evp-fraktion sagte er in brüssel, dass er zwar das recht der ukraine auf selbstverteidigung unterstütze, aber – wie orbán - weder truppen noch waffen in das land schicken werde.': 2,\n",
+ " '„ich glaube, die evp versteht die besondere, empfindliche ungarische lage in diesem krieg“, sagte er.': 2,\n",
+ " 'die weiteren abgeordneten, die von der evp neu aufgenommen wurden, kommen von der familienpartei in deutschland, von zwei neuen parteien aus den niederlanden sowie aus dänemark und der tschechischen republik.': 2,\n",
+ " 'ein abgeordneter von der kndp aus ungarn, die eng mit dem fidesz verknüpft ist, verließ aus protest gegen die aufnahme von tisza, die fraktion.': 2,\n",
+ " 'sie ist nun 189 abgeordnete groß; das sind 13 sitze mehr als im scheidenden parlament.': 2,\n",
+ " 'die zuwächse sind somit das ergebnis der von weber betriebenen expansionsstrategie und nicht von gewinnen der mitgliedsparteien.': 2,\n",
+ " 'allerdings ist es der evp bisher nicht gelungen, die flämischen nationalisten von der n-va zu sich herüberzuziehen.': 2,\n",
+ " 'die partei fühlt sich seit längerem unwohl in der nationalkonservativen fraktion der europäischen konservativen und reformer, die rechts von der evp steht.': 2,\n",
+ " 'ihr kommt nun besonderes gewicht zu, weil sie die belgische parlamentswahl gewonnen hat und mit ihrem vorsitzenden bart de wever den nächsten ministerpräsidenten stellen könnte.': 2,\n",
+ " 'allerdings ist ihr verhältnis zu den flämischen christdemokraten von der partei cd&v, die der evp angehören, derzeit so schlecht, dass sondierungen zu keiner annäherung führten.': 2,\n",
+ " 'auch die fraktion der grünen wählte am mittwoch ihren neuen fraktionsvorstand.': 2,\n",
+ " 'wie erwartet, wurden die beiden spitzenkandidaten im europawahlkampf, terry reintke aus deutschland und bas eickhout aus den niederlanden, als ko-vorsitzende gewählt.': 2,\n",
+ " 'sie bemühen sich, teil der neuen mehrheit im europäischen parlament zu werden.': 2,\n",
+ " '„wir sind der verlässliche und konstruktive partner für eine demokratische proeuropäische mehrheit“, teilte reintke nach ihrer wahl mit.': 2,\n",
+ " 'die evp führt jedoch auch gespräche mit vertretern der ekr-fraktion.': 2,\n",
+ " 'offen ist, ob die sondierungen in eine schriftliche vereinbarung münden, wie sie sich die grünen wünschen.': 2,\n",
+ " 'getragen wird die mehrheit im parlament auf jeden fall von evp, sozialdemokraten und liberalen.': 2,\n",
+ " 'sie kommen zusammen auf 405 von 720 abgeordneten.': 2,\n",
+ " 'die fraktionen von sozialdemokraten und liberalen konstituieren sich erst in der kommenden woche.': 2,\n",
+ " 'bei den liberalen deutet sich an, dass die bisherige vorsitzende valérie hayer abgelöst wird.': 2,\n",
+ " 'hayer verlor als spitzenkandidatin der liste von präsident emmanuel macron zehn sitze in frankreich.': 2,\n",
+ " 'favoritin auf ihre nachfolge ist die frühere belgische premierministerin sophie wilmès.': 2,\n",
+ " 'die wallonische liberale hatte als spitzenkandidatin ihrer partei ein sehr gutes ergebnis geholt.': 2,\n",
+ " 'mit ihr würden sich die gewichte in der fraktion wieder von linksliberalen hin zu wirtschaftsliberalen verschieben.': 2,\n",
+ " 'in keiner kunstform lässt sich die atomexplosionsartige energie von liebe auf den ersten blick so gut darstellen wie im film.': 2,\n",
+ " 'wo sonst findet man bilder für etwas, das sich in worten nur unzulänglich ausdrücken lässt?': 2,\n",
+ " '„es verschlug mir den atem“, wird kathy versuchen, ihr erstes treffen mit benny zu beschreiben.': 2,\n",
+ " 'die kamera findet dafür viel bessere ausdrucksmittel: wenn kathy in einer rauchigen bar benny entdeckt, friert die zeit ein.': 2,\n",
+ " 'die beiden sehen sich an, von einem ende des raums zum anderen, und alles um sie her stürzt ins belanglose.': 2,\n",
+ " 'die musik verebbt, die bewegungen der billardspieler um benny herum verwischen ins nichts, und das licht der schummerigen lampe über dem pooltisch fließt wie ein warmer heiligenschein um seinen körper.': 2,\n",
+ " 'schon hier sind zwei dinge klar: um diese beiden ist es von jetzt an geschehen.': 2,\n",
+ " 'und wir sehen all das mit den augen der jungen frau.': 2,\n",
+ " 'so wie die linse hier bennys durchtrainierte oberarme unter der geöffneten lederweste abtastet, schauen filme sonst auf weibliche körper.': 2,\n",
+ " '„the bikeriders“ aber erzählt von einer männerwelt aus der perspektive von kathy.': 2,\n",
+ " 'es ist ein kluger trick, den der amerikanische regisseur jeff nichols anwendet; geschichten über harte jungs auf schnellen motorrädern kennt man ja ganz anders.': 2,\n",
+ " 'der gonzo-journalist hunter s. thompson schloss sich mitte der sechzigerjahre eine weile den „hells angels“ in kalifornien an, am anderen ende des landes dokumentierte der fotograf danny lyon von 1965 bis 1973 den „outlaws motorcycle club“ in chicago.': 2,\n",
+ " 'beide lassen ehrfurcht und faszination in ihren beschreibungen und dokumentationen mitschwingen.': 2,\n",
+ " 'lyons fotoreportagen liegen „the bikeriders“ zugrunde.': 2,\n",
+ " 'statt jedoch den fotografen von den gesetzlosen schwärmen zu lassen, überlässt nichols eben einer frau das wort, die diese geschichte hautnah miterlebt hat.': 2,\n",
+ " 'sie erzählt also dem journalisten danny (mike faist), wie alles begann.': 2,\n",
+ " 'die treffen der beiden bilden den roten faden, strukturieren die geschichte.': 2,\n",
+ " 'mal im waschsalon sitzend, mal beim kaffee auf ihrer veranda berichtet sie von zwei männern, die ihr leben geprägt haben.': 2,\n",
+ " 'benny (austin butler) ist ein draufgänger, der sich von niemandem etwas vorschreiben lässt, weder vom gesetz noch von seiner freundin.': 2,\n",
+ " 'der einzige mensch, zu dem er aufschaut, ist johnny (tom hardy) – ein mechaniker, der motorräder liebt und sich autorität unter den anderen bikern verschafft hat.': 2,\n",
+ " 'wie ihm das gelang, macht der film gleich zu beginn klar.': 2,\n",
+ " 'als ein aufmüpfiger hüne johnnys entscheidungen in zweifel zieht, fordert der ihn zum zweikampf auf einer schlammigen rennstrecke.': 2,\n",
+ " 'die beiden gehen mit fäusten aufeinander los, treten und boxen, was das zeug hält.': 2,\n",
+ " '„johnny war nicht stärker als der typ, aber er war fieser“, konstatiert kathy, während man sieht, wie der anführer dem herausforderer ohne mit der wimper zu zucken einen finger bricht.': 2,\n",
+ " '„the bikeriders“ verklärt hier aber nicht etwa die schiere brutalität, sondern erforscht mit sinn für nuancen die mechanismen von macht, spürt dabei dem kinonotorischen freiheitsdrang junger amerikaner in den fünfzigerjahren nach und analysiert, wie die ereignisse großer politik auch in die kleinsten gesellschaftsstrukturen zurückspielen.': 2,\n",
+ " 'wenn junge männer aus prekären familien mit sehnsüchtigen blicken den bikern hinterherblicken und danach spontan einen autoscheinwerfer einschlagen, ist das kein platter ausdruck der verführungskunst eines motorradkults, sondern die aufstellung einer gleichung: pubertäre energie plus soziale ungleichheit schafft mythen der rebellion.': 2,\n",
+ " 'dass die selbst johnny trotz all seiner natürlichen autorität nicht mehr unter kontrolle bekommen kann, zeigt sich spätestens, wenn sich dem motorradklub jungs anschließen, die frisch aus dem vietnamkrieg zurückgekehrt sind und neben schlechten manieren auch ihre drogen und traumata mitgebracht haben.': 2,\n",
+ " 'regisseur nichols versucht hier keineswegs, „easy rider“ zu wiederholen.': 2,\n",
+ " 'er nimmt zwar ikonische bilder der motorradfahrten auf, baut sie aber mit eigener ästhetik aus.': 2,\n",
+ " 'und er verlässt sich ansonsten auf den instinkt, der ihn bereits solch einprägsame filme erschaffen ließ wie das jugenddrama „mud“ mit matthew mcconaughey oder das liebesdrama „loving“ über das paar, das die amerikanischen gesetze gegen mischehen außer kraft setzte.': 2,\n",
+ " 'nichols bedient sich dafür ambivalenter figuren und exzellenter schauspieler, die keine platten heldengeschichten erzählen wollen, sondern ihre charaktere zwischen licht und schatten auszubalancieren wissen.': 2,\n",
+ " 'hier greifen sie zusätzlich auf die referenz zu schauspielidolen jener zeit zurück und ziehen ihre rollen auf eine andere ebene, eine des selbstkommentars.': 2,\n",
+ " 'tom hardy arbeitet dabei vor allem mit der faszination seines johnny für marlon brandos gleichnamige figur in „der wilde“.': 2,\n",
+ " 'als der mechaniker diesen film erstmals im fernsehen sieht, springt ein funkeln in seinen blick.': 2,\n",
+ " 'wenn brando dann als anführer einer rockerbande auf die frage, wogegen er eigentlich rebelliere, antwortet: „was hast du im angebot?“, wiederholt hardy das mit leisem murmeln.': 2,\n",
+ " 'johnny hat sein vorbild gefunden, auch wenn er nur dessen autorität als rockerchef imitieren kann.': 2,\n",
+ " 'das sorglose des vorbilds liegt ihm allerdings nicht, und so ist genau das der wesenszug, den er an dem jungen benny, seiner zweiten hand im bikerklub, bewundert.': 2,\n",
+ " 'diesen jungen gibt austin butler, und man versteht spätestens jetzt, wen er sich nicht erst in „the bikeriders“ als darstellervorbild genommen hat.': 2,\n",
+ " 'von der wuscheligen blonden tolle bis zur lässigen pose erlebt man ihn als hommage an james dean, von dem butler sich auch gleich abgeschaut hat, wie man auf coolste art eine zigarette im mundwinkel hängen lässt.': 2,\n",
+ " 'weniger leicht zu entschlüsseln ist schon michael shannon, der die autoritären tendenzen jener männer in der bande verkörpert, die sich nach starken führern sehnen, und der „the walking dead“-star norman reedus, der das gegensatzpaar loyalität und irrsinn zusammenbinden darf.': 2,\n",
+ " 'die größte überraschung aber ist hier jodie comer.': 2,\n",
+ " 'gerade konnte man sie noch im kino in „the end we start from“ als britin mit baby gegen den untergang ihrer welt in der klimakatastrophe kämpfen sehen, da zeigt sie schon, wie man mit einem neuen akzent und einer bisher nicht eingenommenen haltung die komplette persönlichkeitsausstrahlung ändern kann.': 2,\n",
+ " 'comer legt kathy als furchtlose frau mit trockenem humor an, die genau beobachtet, in welche machtkämpfe sich ihr geliebter ziehen lässt und wie sich der bikerklub vom rennfahrerverein zur kriminellen organisation entwickelt.': 2,\n",
+ " 'freiheitsträume, lernt man hier, sind immer bedroht – und nur wer großes glück hat, kommt lebend davon.': 2,\n",
+ " 'die beiden am tresen haben die besten plätze.': 2,\n",
+ " 'ihr tisch steht direkt an der anrichteküche.': 2,\n",
+ " 'und das ist der ort, an dem bei julio pizarro die musik spielt.': 2,\n",
+ " 'mit beneidenswerter ruhe und gelassenheit bringt der peruaner auf der großen, von kupfernen wärmelampen beschienenen arbeitsfläche einen gang nach dem anderen auf die teller – und das paar am tresen hat uneingeschränkte sicht auf die filigrane handarbeit, mit der hier kleine kulinarische kunstwerke in serie entstehen.': 2,\n",
+ " 'mit ihrem gestreiften strickpullover und seinem poloshirt sehen die beiden nicht aus wie typische gourmet-gäste – aber sie sind nicht zum ersten mal hier.': 2,\n",
+ " 'der tisch am tresen ist etwas für stammgäste.': 2,\n",
+ " 'marcel dörflinger-oster platziert sie gerne in der nähe des chefs, wenn sie es möchten.': 2,\n",
+ " 'les commentaires ont été désactivés.': 2,\n",
+ " \"en club, c'est juste la ville.\": 2,\n",
+ " 'je pense que cela montre beaucoup de choses.': 2,\n",
+ " 'cet article (2/2) est issu du dossier': 2,\n",
+ " 'jamais dissous mais en sommeil depuis 2017, le gud avait annoncé son retour fin 2022.': 2,\n",
+ " \"connu pour ses actions violentes, le gud revient régulièrement sous les feux de l'actualité.\": 2,\n",
+ " 'parmi eux, marc de caqueray-valmenier, chef présumé des zouaves, condamné et incarcéré à plusieurs reprises ces dernières années.': 2,\n",
+ " 'het adviesbureau vroeg iedereen die wilde meewerken aan het onderzoek zich te melden en garandeerde anonimiteit.': 2,\n",
+ " 'ambtenaren – sommigen werken er al tientallen jaren – zouden het lastig vinden om elkaar aan te spreken op gedrag en binnen de „gelderse cultuur, waarin conflicten worden vermeden”, wordt dat al snel gezien als aanval.': 2,\n",
+ " 'rolf schuttenhelm': 2,\n",
+ " 'redacteur klimaat': 2,\n",
+ " 'danmark\\n \\n \\n 19. jun.': 2,\n",
+ " 'danmark\\n \\n 19. jun.': 2,\n",
+ " 'sundhed\\n \\n \\n 19. jun.': 2,\n",
+ " 'sundhed\\n \\n 19. jun.': 2,\n",
+ " 'arne: jeg var en af dem, der fulgte royal run på skærmen.': 2,\n",
+ " 'jeg indrømmer, at jeg flere gange tænkte: bare det var mig, der var med.': 2,\n",
+ " 'bare det var mig, der kunne løbe 5 km.': 2,\n",
+ " 'kan du give en opskrift på, hvordan jeg træner mig op til at løbe 5 km?': 2,\n",
+ " 'jeg er 55 år.': 2,\n",
+ " 'jeg går og cykler en del, men jeg er ikke vant til at løbe.': 2,\n",
+ " 'på kontoret sidder jeg foran en skærm det meste af dagen.': 2,\n",
+ " 'bente klarlund pedersen: sundhedsstyrelsen anbefaler, at vi motionerer mindst 30 minutter om dagen de fleste af ugens dage.': 2,\n",
+ " 'lad denne anbefaling være rammen for din målsætning om at løbe 5 km kontinuerligt.': 2,\n",
+ " 'hvis og når du opfylder ’30 minutter om dagen’ i rask gang, skal du langsomt konvertere gang til løb.': 2,\n",
+ " 'det er lodtrækning til tredje runde allerede 22. juli, altså inden fcm’s første opgør mod enten ballkani eller santa coloma.': 2,\n",
+ " 'klarer fcm sig videre til fjerde runde – også kaldet playoffrunden – i champions league-kvalifikation, vil holdet være sikret mindst en plads i europa leagues gruppespil.': 2,\n",
+ " 'også silkeborg if har været i bowlen i europa league-kvalifikationen.': 2,\n",
+ " 'pokalvinderen skal op mod molde i anden runde af europa leagues anden kvalifikationsrunde.': 2,\n",
+ " 'dansk økonomi kommer til at vokse med to procent i 2024.': 2,\n",
+ " 'det vurderer den internationale valutafond, imf, i en årlig gennemgang af dansk økonomi, som er blevet offentliggjort onsdag.': 2,\n",
+ " 'væksten vil blive drevet af medicinalindustrien og genåbningen af tyra-feltet, som er er et naturgasfelt.': 2,\n",
+ " 'det samme vurderede nationalbanken i sin seneste halvårlige vækstprognose for dansk økonomi, som udkom i marts.': 2,\n",
+ " 'her var det dog vurderingen, at økonomien vil vokse 2,4 procent i år.': 2,\n",
+ " 'imf er en organisation af 190 lande, som blandt andet arbejder for at fremme globalt pengesamarbejde og sikre finansiel stabilitet.': 2,\n",
+ " 'økonomer fra organisationen har brugt de seneste uger på at interviewe folk fra finansministeriet, nationalbanken og andre relevante myndigheder her i landet.': 2,\n",
+ " 'det har man gjort for at få et indtryk af, hvordan den danske økonomi har det.': 2,\n",
+ " 'på den baggrund kommer valutafonden også med anbefalinger til fremtiden.': 2,\n",
+ " 'den overordnede konklusion i rapporten er, at den danske økonomi står et robust sted.': 2,\n",
+ " 'kigger man lidt længere frem, er der udsigt til, at væksten i dansk økonomi kommer til at falde en anelse.': 2,\n",
+ " 'det skyldes, at eksportvæksten i medicinalindustrien vil aftage.': 2,\n",
+ " 'valutafonden har i sin gennemgang også noteret sig, at den ser tegn på, at arbejdsmarkedets momentum viser svaghedstegn.': 2,\n",
+ " 'beskæftigelsen har ellers trodset spådomme om tilbagegang i en lang periode.': 2,\n",
+ " 'derfor anbefales det også, at man gennemfører strukturelle reformer for at understøtte arbejdsmarkedet.': 2,\n",
+ " 'novellerne indeholdt meget voldsomme beskrivelser af kidnapninger af unge piger, som blev holdt indespærret, mens jeg-fortælleren forgreb sig på sine værgeløse ofre.': 2,\n",
+ " 'det nægter han.': 2,\n",
+ " 'havnen er en af vores vigtigste arbejdspladser, siger borgmesteren.': 2,\n",
+ " 'det sker i forbindelse med præsident putins besøg i pyongyang i dag.': 2,\n",
+ " '- rusland udelukker ikke et militærteknisk samarbejde med nordkorea i overensstemmelse med det dokument, der i dag er blevet underskrevet, siger vladimir putin.': 2,\n",
+ " 'elle en était toutefois sortie en 2017.': 2,\n",
+ " 'miljøaktivister har sprøjtet orange maling på flere af stenene på den verdenskendte stenformation stonehenge, der ligger omkring 135 kilometer fra london.': 2,\n",
+ " 'det fremgår onsdag af et opslag på det sociale medie x fra gruppen just stop oil.': 2,\n",
+ " 'her kan man se demonstranter i hvide t-shirts sprøjte maling på stonehenge, mens flere personer forsøger at stoppe dem.': 2,\n",
+ " 'to er blevet anholdt, oplyser lokalt politi i en meddelelse ifølge nyhedsbureauet reuters.': 2,\n",
+ " 'gruppen just stop oil er blevet kendt efter flere lignende aktioner i storbritannien.': 2,\n",
+ " 'just stop oil har blokeret trafikken på vigtige færdselsårer, forstyrret kulturbegivenheder og kastet suppe på et billede af den hollandske maler vincent van gogh.': 2,\n",
+ " 'gruppen ønsker, at den britiske regering stopper med at udvinde og afbrænde olie, gas og kul i 2030.': 2,\n",
+ " 'stonehenge er et forhistorisk monument, der ligger i wiltshire i det sydlige england.': 2,\n",
+ " 'det består af en formation af en række sten, der er over fire meter høje.': 2,\n",
+ " 'det er en af englands mest berømte attraktioner.': 2,\n",
+ " 'stenformationen menes at være bygget ad seks omgange mellem år 3000 og år 1500 før vores tidsregning.': 2,\n",
+ " 'stonehenge optræder på unescos verdensarvsliste sammen med andre attraktioner som taj mahal i indien og de store pyramider i giza i egypten.': 2,\n",
+ " 'det er organisationen english heritage, som står for at administrere og bevare stonehenge.': 2,\n",
+ " 'tegn et gratis prøveabonnement og få adgang til alt plus-indhold på ing, version2 og radar, helt uden binding eller betalingsoplysninger.': 2,\n",
+ " 'få en forlænget erhvervsprøvemed et erhvervsabonnement kan du få en forlænget prøveperiode.': 2,\n",
+ " 'indtast e-mail *': 2,\n",
+ " 'remove_circle': 2,\n",
+ " 'du accepterer vores abonnementsbetingelser for plus, når du tegner et abonnement eller prøveabonnement på plus.': 2,\n",
+ " 'læs betingelserne her.': 2,\n",
+ " 'du accepterer teknologiens mediehus’ brugerbetingelser og persondatapolitik.': 2,\n",
+ " 'du accepterer derudover følgende kontaktbetingelser: teknologiens mediehus må lejlighedsvis kontakte dig om arrangementer, konkurrencer, analyser, nyheder, job, undersøgelser og tilbud via e-mail.': 2,\n",
+ " 'i e-mails fra teknologiens mediehus kan der forekomme markedsføring fra samarbejdspartnere.': 2,\n",
+ " 'du kan til enhver tid indstille dine kontaktpræferencer, under menupunktet ‘tilladelser & services’ på din ing/profil.': 2,\n",
+ " 'har du allerede et plus-abonnement eller klip?': 2,\n",
+ " 'log ind east': 2,\n",
+ " 'da du er ved at tilmelde dig en gratis prøve beder vi dig hjælpe os med at gøre vores indhold mere relevant for dig, ved at vælge et eller flere emner der interesserer dig.': 2,\n",
+ " 'du skal vælge en adgangskode til når du fremover skal logge ind på din brugerkonto.': 2,\n",
+ " 'vælg adgangskode *': 2,\n",
+ " 'følger sagen.': 2,\n",
+ " 'årets tivolirevy består af lisbet dahl, thomas eje, rikke buch bendtsen, rikke bilde og mikkel becker hilgart.': 2,\n",
+ " 'herunder kan du læse b.t.s anmeldelse af årets tivolirevy.': 2,\n",
+ " 'læs også:\\xa0strategens bedste bud: her er 5 mulige vinderaktier': 2,\n",
+ " 'der er masser af gode muligheder for at spare penge på madbudgettet.': 2,\n",
+ " 'opdateres...': 2,\n",
+ " 'den historie kan du læse her.': 2,\n",
+ " '»at preppe er nok en opgave, der lægger sig oven i at drage omsorg for familien.': 2,\n",
+ " 'læs om det her.': 2,\n",
+ " 'lyt i spotify, på apple podcast eller ved at trykke play herunder.': 2,\n",
+ " \"i b.t.s podcast 'kongehuset bag kulissen' sætter b.t.s kongehusreporter silla bakalus sammen med eksperter hver uge fokus på ugens vigtigste royale historie.\": 2,\n",
+ " 'læs også:\\xa0globale kæmpeinvestorer skruer ned for tech - men festen er langt fra slut, mener dansk chefstrateg': 2,\n",
+ " 'læs også:\\xa0her mener dansk storbank, at der er mest aktiepotentiale lige nu': 2,\n",
+ " 'læs også:\\xa0dansk biotekselskab udsteder nye aktier - aktien banker op': 2,\n",
+ " '- hvorfor skulle han så tildække hendes hoved under hele forløbet.': 2,\n",
+ " 'hun har et pudebetræk over hovedet.': 2,\n",
+ " 'social- og boligministeren afviser enhver kritik af, at regeringen ville sløjfe aftalte bevillinger til en række integrationsprojekter.': 2,\n",
+ " 'det vakte vrede hos oppositionspartier og berørte organisationer.': 2,\n",
+ " 'politik\\n \\n \\n 20. jun.': 2,\n",
+ " 'politik\\n \\n 20. jun.': 2,\n",
+ " 'social- og boligministeren viste ingen tegn på fortrydelse eller forståelse, da hun onsdag eftermiddag skulle forklare sig på et velbesøgt samråd.': 2,\n",
+ " 'emnet for samrådet var de besparelser på politisk aftalte integrationsprojekter, som regeringen tidligere i år planlagde at gennemføre, men efter massiv kritik valgte at aflyse for 2024.': 2,\n",
+ " 'besparelserne er fortsat på bordet for 2025.': 2,\n",
+ " 'på samrådet deltog tre ministre, der i løbet af halvanden time skulle svare på forskellige versioner af spørgsmålet om, hvorvidt partierne på christiansborg kan regne med de aftaler, de indgår med regeringen.': 2,\n",
+ " 'partierne var oprørte over, at en aftale om integrationsindsatser indgået med socialministeren stod til at blive ophævet på grund af sparekrav vedtaget i en anden aftale om kriminalforsorgen med justitsministeren.': 2,\n",
+ " 'internationalt\\n \\n \\n 20. jun.': 2,\n",
+ " 'det oplyser det amerikanske stormcenter nhc torsdag.': 2,\n",
+ " 'stormen befinder sig omkring 200 kilometer øst for den mexicanske havneby tampico med vindstyrke på op til 80 kilometer i timen, lyder det fra nhc.': 2,\n",
+ " 'dog er albertos vindstyrke fortsat under orkanstyrke.': 2,\n",
+ " 'der er registreret mindst ét dødsfald som følge af stormen alberto.': 2,\n",
+ " 'det drejer sig om en 15-årig dreng, som blev revet med af strømmen i en flod og druknede ud for byen monterrey i delstaten nuevo leon.': 2,\n",
+ " 'det melder lokale beredskabsstyrker.': 2,\n",
+ " 'det oplyser dyre sønnicksen, vagtchef ved københavns politi, til ritzau.': 2,\n",
+ " 'politiet arbejder desuden på at få udleveret oplysninger om, hvem der har lejet bilen.': 2,\n",
+ " 'det regner nemlig med, at det er ham, som har kørt bilen i vandet.': 2,\n",
+ " 'i alt 52 personer i danmark er nu blevet smittet med salmonella.': 2,\n",
+ " 'det viser en opdateret opgørelse fra statens serum institut, som dækker over april, maj og juni, onsdag aften.': 2,\n",
+ " 'de syge er 32 mænd og 29 kvinder.': 2,\n",
+ " 'næsten halvdelen af de smittede var i region hovedstaden, og patienterne var op til 85 år gamle.': 2,\n",
+ " 'det vides endnu ikke, præcist hvor salmonellabakterien stammer fra, men fra ssi lød det i sidste uge, at de registrerede tilfælde formentlig kun er toppen af isbjerget.': 2,\n",
+ " 'i den forbindelse sagde luise müller også, at forklaringerne fra patienterne tydede på, at infektionerne stammede fra hakket oksekød.': 2,\n",
+ " 'det er dog endnu ikke bekræftet.': 2,\n",
+ " 'i maj blev 64 patienter i danmark smittet med en salmonellatype, der viste sig at stamme fra hakket oksekød fra england.': 2,\n",
+ " 'der kan være bakterier i hakket kød, som kan føre til sygdom.': 2,\n",
+ " 'det kan være salmonella, men det kan også være særligt farlige e. coli-bakterier.': 2,\n",
+ " 'derfor råder fødevarestyrelsen blandt andet til, at man køber hakket kød, som er specielt beregnet til tatar, hvis man ønsker at spise dette.': 2,\n",
+ " 'derudover bør man vaske hænder, inden man går i gang med madlavningen og efter at have rørt ved råt kød.': 2,\n",
+ " 'man bør også undgå at smage på råt kød, holde det adskilt fra den spiseklare mad samt gennemstege eller gennemkoge hakket kød.': 2,\n",
+ " 'salmonella findes hos dyr og kan smitte mennesker via fødevarer, som er forurenede med bakterien.': 2,\n",
+ " 'infektion med salmonella giver typisk diarré, ondt i maven, kvalme og feber.': 2,\n",
+ " 'ved alvorlige og vedvarende tilfælde opfordres man til at gå til lægen.': 2,\n",
+ " 'forhandlingerne om, hvordan danmark skal nå de klimamål, der er sat op, er i fuld gang.': 2,\n",
+ " 'men en af hovedpersonerne er sat ud af spillet på ubestemt tid.': 2,\n",
+ " 'det skriver han selv i et opslag på linkedin.': 2,\n",
+ " 'lars aagaard har endnu ikke fået en diagnose og ved derfor heller ikke, hvor længe han skal være indlagt.': 2,\n",
+ " 'lars aagaard er en af de fem ministre, der repræsenterer regeringen i forhandlingerne om den såkaldte grønne trepart, der gerne skal munde ud i en aftale, der mindsker landbrugets co2-udledning de kommende år.': 2,\n",
+ " 'de øvrige parter er landbruget, fagforeninger, kommunerne og miljøorganisationer.': 2,\n",
+ " 'forhandlingerne ledes af den tidligere formand for folketinget henrik dam kristensen.': 2,\n",
+ " 'forhandlingerne begyndte i januar, og planen er, at der skal ligge et udspil klar inden udgangen af denne måned.': 2,\n",
+ " 'min kærlighed til ’the boys’ er båret af den skarpe politiske satire, den elegante kropshorror og den kombination af frastødelse og ømhed, karaktererne vækker.': 2,\n",
+ " 'der er mindre af det hele i sæson 4.': 2,\n",
+ " 'sådan forløb kampen:': 2,\n",
+ " 'de tyske værter er som det første hold klar til ottendedelsfinalerne ved em.': 2,\n",
+ " 'efter at have slået skotland 5-1 i åbningskampen leverede tyskerne endnu en overbevisende præstation onsdag.': 2,\n",
+ " 'ungarn blev slået 2-0, og med seks point efter to gruppekampe er tyskerne sikret avancement.': 2,\n",
+ " 'efter en god og optimistisk ungarsk start var det tyskerne, som satte sig tungt på kampen.': 2,\n",
+ " 'med erfarne toni kroos som dirigent spillede tyskerne på de mange offensive tangenter, der er på holdet.': 2,\n",
+ " 'ungarn havde travlt med at afvise de tyske tilnærmelser tæt på eget felt, mens den hurtige tyske bagkæde dygtigt fik lukket ned for de sporadiske kontraforsøg fra ungarerne.': 2,\n",
+ " 'ilkay gündogan kæmpede hårdt for en bold inde i feltet, og efter lidt klumpspil fik han bugseret bolden hen til musiala, som i relativt fri position kunne sparke bolden i kassen.': 2,\n",
+ " 'det kunne være blevet til flere tyske scoringer før pausen, men ungarn havde også et par chancer.': 2,\n",
+ " 'manuel neuer måtte blandt andet diske op med en stor redning på et frisparksforsøg fra liverpools dominik szoboszlai.': 2,\n",
+ " 'i halvlegens tillægstid fik ungarn bolden i mål, men linjedommeren vinkede korrekt for offside.': 2,\n",
+ " 'den tyske dominans aftog en smule efter pausen.': 2,\n",
+ " 'ungarerne fornemmede, at der var muligheder for at arbejde sig ind i kampen.': 2,\n",
+ " 'især roland sallai voldte tyskland en del problemer.': 2,\n",
+ " 'den hurtige offensivspiller lagde sig ofte ud til tyskernes højreback joshua kimmich og fik skabt farlige situationer med både driblinger og indlæg.': 2,\n",
+ " 'bedst som ungarn vejrede morgenluft, viste værtsnationen igen, hvorfor den skal regnes som en potentiel europamester.': 2,\n",
+ " 'efter 66 minutter kombinerede man på forbilledlig vis, og slutteligt blev bolden lagt til rette for gündogan skråt tilbage i feltet.': 2,\n",
+ " 'med indersiden fordoblede han føringen og punkterede den ungarske tro på point.': 2,\n",
+ " 'på cruisekontrol styrede tyskerne mod sejren, uden at ungarn på noget tidspunkt var tæt på at ændre på udfaldet.': 2,\n",
+ " 'træner julian nagelsmann kunne lade stuttgart-spillerne i truppen komme på banen til hyldest på deres normale hjemmebane og lidt em-minutter.': 2,\n",
+ " 'tyskland skal i sidste gruppekamp møde schweiz i frankfurt.': 2,\n",
+ " '- kan man afvise, at det forholder sig på den måde?': 2,\n",
+ " 'med vores brevkasse spørg videnskaben kan du stille spørgsmål til forskerne om alt fra prutter og sjove bynavne til kvantecomputere og livets oprindelse.': 2,\n",
+ " '/ritzau/afp': 2,\n",
+ " 'sie ist in den herzen der menschen verwurzelt.': 2,\n",
+ " 'es müsse eine alternative für die hamas auf politischer ebene gefunden werden, um sie im gazastreifen zu ersetzen, forderte hagari in dem interview weiter.': 2,\n",
+ " 'über die zerstörung der hamas zu reden, führe die öffentlichkeit in die irre.': 2,\n",
+ " 'jamal musiala ist so frei, ilkay gündogan auch – und kai havertz fühlt sich als stürmer immer wohler.': 2,\n",
+ " '19 juni 2024': 2,\n",
+ " '„het zal wel loslopen.”': 2,\n",
+ " 'nu ga ik tot het gaatje met die lui.': 2,\n",
+ " 'ze zeiden dat beveiliging niet nodig was, terwijl ze dit wisten.': 2,\n",
+ " 'guus dietvorst': 2,\n",
+ " 'redacteur politiek': 2,\n",
+ " 'fleur launspach': 2,\n",
+ " 'correspondent vk en ierland': 2,\n",
+ " 'power up with unlimited access to wired.': 2,\n",
+ " \"get best-in-class reporting that's too important to ignore for just $2.50 $1 per month for 1 year.\": 2,\n",
+ " 'includes unlimited digital access and exclusive subscriber-only content.': 2,\n",
+ " '15 hours ago': 2,\n",
+ " 'by\\xa0hafsa khalil,\\xa0bbc news': 2,\n",
+ " 'the war in ukraine has shifted the balance of power between moscow, pyongyang and beijing': 2,\n",
+ " 'new episodes every week.': 2,\n",
+ " 'june 19, 2024': 2,\n",
+ " 'hbr learning': 2,\n",
+ " 'digital intelligence course': 2,\n",
+ " 'accelerate your career with harvard managementor®.': 2,\n",
+ " 'hbr learning’s online leadership training helps you hone your skills with courses like digital intelligence .': 2,\n",
+ " 'earn badges to share on linkedin and your resume.': 2,\n",
+ " 'access more than 40 courses trusted by fortune 500 companies.': 2,\n",
+ " \"excel in a world that's being continually transformed by technology.\": 2,\n",
+ " 'profitez du pack canal + pour regarder espagne - italie en streaming': 2,\n",
+ " 'profitez de ce bon plan molotov pour regarder en streaming espagne - italie': 2,\n",
+ " 'on a l’impression de se partager un secret.': 2,\n",
+ " \"(laurent le crabe/l'équipe)\": 2,\n",
+ " 'dominique de villepin était notamment interrogé sur la prise de position de serge klarsfeld, historien rescapé de la shoah, qui a annoncé quelques jours plus tôt qu’il voterait pour le rn.': 2,\n",
+ " 'notre librairie de quartier, on l’aime.': 2,\n",
+ " 'décryptage.': 2,\n",
+ " '«\\xa0j’étais tellement content d’être face à clotaire.': 2,\n",
+ " 'enormes carteles con las fotos de los dos líderes adornaban los edificios circundantes durante la ceremonia de bienvenida.': 2,\n",
+ " 'pese a la situación económica, pyongyang parece no haber escatimado en recursos para esta visita, con la esperanza, por supuesto, de que dé sus frutos, indica khalil.': 2,\n",
+ " 'putin le obsequió a su homólogo un lujoso automóvil ruso aurus, una daga de almirante y un juego de té, informaron los medios estatales rusos, citando al asistente presidencial yuri ushakov.': 2,\n",
+ " 'esta prevista una fiesta de té y un concierto de gala en la noche.': 2,\n",
+ " 'rejser\\n \\n \\n 20. jun.': 2,\n",
+ " 'rejser\\n \\n 20. jun.': 2,\n",
+ " '»vi har fundet en god midlertidig afløser for lisbet dahl i lone rødbroe, der gennem mange år har underholdt på førende revyscener rundt om i danmark.': 2,\n",
+ " 'foreningen bag folkemødet på bornholm skal have ny formand.': 2,\n",
+ " 'den hidtidige formand, vibe klarup, stopper på posten, som hun har bestridt de seneste fire år.': 2,\n",
+ " 'det fremgår af en pressemeddelelse fra foreningen folkemødet.': 2,\n",
+ " 'om beslutningen siger den afgående formand:': 2,\n",
+ " 'hun er generalsekretær i amnesty international danmark og overtog posten som formand i 2020 efter jann sjursen.': 2,\n",
+ " 'folkemødets bestyrelse skal nu på jagt efter en efterfølger til formandsposten.': 2,\n",
+ " 'bestyrelsen har konstitueret sig med et delt formandskab mellem de to hidtidige næstformænd, søs marie serup og carsten grønning.': 2,\n",
+ " 'sport\\n \\n \\n 20. jun.': 2,\n",
+ " 'sport\\n \\n 20. jun.': 2,\n",
+ " 'ifølge det serbiske medie rts opfordrede de to fangrupperinger til drab på serberne.': 2,\n",
+ " '»først og fremmest vil jeg takke vores fans for støtten i kampen mod england, og jeg håber på, vi kan slå slovenien.': 2,\n",
+ " 'men det, der skete, er skandaløst, og vi vil bede uefa om sanktioner.': 2,\n",
+ " 'serbien spiller torsdag en potentiel skæbnekamp mod slovenien i danmarks gruppe, og på trods af truslen om at trække sig er der intet, der endnu tyder på, at serberne ikke stiller til kampstart.': 2,\n",
+ " 'epidemi af kødædende bakterier har': 2,\n",
+ " 'ramt danmark.': 2,\n",
+ " 'hundreder betaler af': 2,\n",
+ " 'på »coronagæld« med sygdom og død': 2,\n",
+ " 'europa sover, siger mærsks': 2,\n",
+ " 'chef: »jeg er klart bekymret«': 2,\n",
+ " 'medier: ukraines sikkerhedstjeneste': 2,\n",
+ " 'slår til igen – forsøger at lamme': 2,\n",
+ " 'europas kokainkonge afslører sig selv:': 2,\n",
+ " 'hans private billeder og ord viser os': 2,\n",
+ " 'sandheden om livet som gangster': 2,\n",
+ " 'erhvervslivet jubler: »det er en': 2,\n",
+ " 'forbedring i forhold til, at det bare': 2,\n",
+ " 'er noget, skat har fundet på«': 2,\n",
+ " 'forsvarer: mette': 2,\n",
+ " 'frederiksen fik': 2,\n",
+ " 'ikke piskesmæld': 2,\n",
+ " 'redaktør roser københavns': 2,\n",
+ " 'nye stadsarkitekt.': 2,\n",
+ " 'er alligevel et problem': 2,\n",
+ " 'strejke hos postnord forsinker brevforsendelser i flere dage': 2,\n",
+ " '»jeg var tæt på kanten«: pludselig': 2,\n",
+ " 'blev hans højre underben': 2,\n",
+ " 'angrebet af kødædende bakterier': 2,\n",
+ " 'serbien fra danmarks gruppe': 2,\n",
+ " 'truer med at trække sig fra em': 2,\n",
+ " 'korrespondent spiste': 2,\n",
+ " 'forbudte nudler forkert.': 2,\n",
+ " 'nu spiser han dem igen': 2,\n",
+ " 'dansk socialt medie': 2,\n",
+ " 'er tilbage: 10.000': 2,\n",
+ " 'tilmeldinger på seks': 2,\n",
+ " 'til tivolirevyen': 2,\n",
+ " 'folkemødet trækker sig': 2,\n",
+ " 'særdeles dyster læsning for': 2,\n",
+ " 'rishi sunak: han kan blive': 2,\n",
+ " 'den første nogensinde': 2,\n",
+ " 'de har udsigt til danmarks': 2,\n",
+ " 'højeste løn.': 2,\n",
+ " 'oskar allerslev': 2,\n",
+ " 'valgte uddannelsen for': 2,\n",
+ " 'pengenes skyld': 2,\n",
+ " 'giver forskere deres bud på hvorfor': 2,\n",
+ " 'se de »barbariske« scener: kinas': 2,\n",
+ " '»pirater« angreb med økser og spyd': 2,\n",
+ " 'festen var præcis, som den': 2,\n",
+ " 'skulle være.': 2,\n",
+ " 'en skaldet engelsk': 2,\n",
+ " 'fodboldfan nåede grænsen ved': 2,\n",
+ " 'en lille, lyshåret, tysk ung kvinde': 2,\n",
+ " 'adam holm advarer': 2,\n",
+ " 'om »situationens': 2,\n",
+ " 'alvor«: »nu er': 2,\n",
+ " 'her er formkurven hos de': 2,\n",
+ " 'borgerlige: én har helt uventet': 2,\n",
+ " 'grund til at være bekymret': 2,\n",
+ " 'jeg er sådan set glad for, at denne': 2,\n",
+ " 'film findes, men hold kæft hvor': 2,\n",
+ " 'er disse skuespillere irriterende': 2,\n",
+ " 'bemærkelsesværdig rekord for danskere i job': 2,\n",
+ " 'der findes et hav af film om': 2,\n",
+ " 'anden verdenskrig.': 2,\n",
+ " 'sikkert få dig på grådens rand': 2,\n",
+ " 'forud for debat': 2,\n",
+ " 'antal unge uden': 2,\n",
+ " 'uddannelse og job': 2,\n",
+ " 'stiger – tesfaye': 2,\n",
+ " 'varsler udspil': 2,\n",
+ " 'firedobler overskuddet': 2,\n",
+ " 'berlingske erfarer: så meget': 2,\n",
+ " 'lettes virksomhedernes skat i dag': 2,\n",
+ " 'danmark var i problemer – nu venter': 2,\n",
+ " 'favoritterne: »vi skal have drømmen«': 2,\n",
+ " 'hussalget er nu': 2,\n",
+ " 'over niveauet i': 2,\n",
+ " 'tiden før corona': 2,\n",
+ " 'nu venter det': 2,\n",
+ " 'ubetinget stærkeste': 2,\n",
+ " 'hold i gruppen:': 2,\n",
+ " '»danmark får det': 2,\n",
+ " '150.000 pakker jodtabletter': 2,\n",
+ " 'på vej til apotekerne': 2,\n",
+ " 'nu skal danskerne preppe, mens': 2,\n",
+ " 'myndighederne halter bagefter: troels': 2,\n",
+ " 'lund afviser, at vi er uforberedte': 2,\n",
+ " 'jobbet er kun et hak bedre': 2,\n",
+ " 'end at forsvare olieselskaber': 2,\n",
+ " 'og tobaksindustrien – men': 2,\n",
+ " 'det kan også være et': 2,\n",
+ " 'drømmeexit fra dansk politik': 2,\n",
+ " 'midt i afgørende forhandlinger: klimaminister': 2,\n",
+ " 'indlagt med »voldsomme rygsmerter«': 2,\n",
+ " 'rusland og nordkorea vil': 2,\n",
+ " 'omstyrte verdensordenen.': 2,\n",
+ " 'bestyrelse enige: grønt lys for elge i nordsjælland': 2,\n",
+ " 'en af sunaks livvagter er': 2,\n",
+ " 'anholdt og suspenderet': 2,\n",
+ " 'efter mistanke om': 2,\n",
+ " 'væddemål om valgdato': 2,\n",
+ " '78-årig skuespiller har det efter omstændighederne godt, oplyser kulturdirektør i tivoli.': 2,\n",
+ " 'kulturdirektør frederik wiedemann siger, at 78-årige dahl \"efter omstændighederne har det godt\" og \"vender tilbage til revyen, når hun er rask igen\".': 2,\n",
+ " '- vi har fundet en god midlertidig afløser for lisbet dahl i lone rødbroe, der gennem mange år har underholdt på førende revyscener rundt om i danmark.': 2,\n",
+ " 'det er en løsning, som lisbet dahl også er glad for, siger frederik wiedemann.': 2,\n",
+ " 'lisbeth dahl har medvirket i et stort antal film, teaterstykker og revyer, og hun er ifølge tivolis hjemmeside instruktør og kunstnerisk leder af årets tivolirevy.': 2,\n",
+ " 'året før - i 2021 - havde skuespilleren ligeledes en sygeperiode under cirkusrevyen.': 2,\n",
+ " 'det skyldes dengang stress \"efter et sygdomsforløb, der har tæret på kræfterne\", blev det oplyst i en pressemeddelelse.': 2,\n",
+ " 'den første harry potter-bog blev i 1997 trykt i 500 eksemplarer, da der var usikkerhed om dens potentiale.': 2,\n",
+ " 'en sjælden førsteudgave af harry potter-bogen \"harry potter og de vises sten\" er blevet solgt på en auktion i skotland for 45.201 pund - svarende til knap 400.000 danske kroner.': 2,\n",
+ " 'det skriver nyhedsbureauet dpa.': 2,\n",
+ " 'i første omgang blev bogen i 1997 blot trykt i 500 eksemplarer, fordi der var usikkerhed om, hvor populær den ville blive.': 2,\n",
+ " 'bogserien, som den britiske forfatter j.k. rowling står bag, viste sig dog at blive ekstremt populær på verdensplan.': 2,\n",
+ " 'bbc har tidligere skrevet, at bogserien er blandt de bedst sælgende nogensinde og har solgt over 600 millioner eksemplarer på verdensplan.': 2,\n",
+ " 'derudover er den siden blevet filmatiseret.': 2,\n",
+ " 'bogen var spået til at blive solgt for mellem 40.000 og 60.000 pund.': 2,\n",
+ " 'den blev solgt onsdag hos auktionshuset lyon & turnbull i hovedstaden edinburgh.': 2,\n",
+ " '\"harry potter og de vises sten\" er den første i bogserien på i alt syv bøger.': 2,\n",
+ " 'her følger man drengen harry, der viser sig at være troldmand og begynder på skolen hogwarts.': 2,\n",
+ " 'derudover er der udgivet andre bøger i samme univers.': 2,\n",
+ " '- en førsteudgave af \"harry potter og de vises sten\" er en usædvanligt sjælden bog at finde i enhver stand.': 2,\n",
+ " 'og en i så fremragende stand kunne godt blive kaldt juvelen i enhver harry potter-samlers krone, har cathy marsden, chef for bøger og manuskripter hos auktionshuset, udtalt.': 2,\n",
+ " 'ud over harry potter-bogen blev der også solgt andre bøger på samme auktion.': 2,\n",
+ " 'det gjaldt blandt andet en kopi af ian flemings \"casino royale\", som er den første roman i spionserien om james bond, der også er blevet filmatiseret.': 2,\n",
+ " 'den var vurderet til at koste mellem 30.000 og 50.000 pund og blev solgt for 38.951 pund - knap 344.000 danske kroner, skriver dpa.': 2,\n",
+ " 'ifølge cathy marsden er værker af \"litterære giganter\" som rowling og ian fleming fortsat meget populære, når de skal på auktion.': 2,\n",
+ " 'på auktionen kom en førsteudgave af bogen \"when we were very young\" af peter plys-forfatteren a.': 2,\n",
+ " 'a. milne også under hammeren.': 2,\n",
+ " 'den blev solgt for 15.120 pund - omkring 133.000 kroner.': 2,\n",
+ " 'mod tidligere 3,5-5 pct.': 2,\n",
+ " 'mod tidligere 1,7-1,8 mia.': 2,\n",
+ " '18+ | spil ansvarligt | regler og vilkår gælder | stopspillet – ring til 70 22 28 25 | udeluk dig via rofus\\xa0|\\xa0der tages forbehold for fejl og ændringer.': 2,\n",
+ " 'dagens øvrige kampe': 2,\n",
+ " 'ballerina sko er et ikonisk valg, der kombinerer elegance og komfort på fornem vis.': 1,\n",
+ " 'disse sko er kendetegnet ved deres flade hæl og spidse tå, hvilket giver en raffineret og feminin silhuet.': 1,\n",
+ " 'samtidig er de utroligt behagelige at have på, takket være deres fleksible materialer og polstrede indersål.': 1,\n",
+ " 'uanset om du skal til en særlig begivenhed eller blot ønsker et stilfuldt, men behageligt fodtøj til hverdagsbrug, er ballerina sko et oplagt valg.': 1,\n",
+ " 'de fås i et bredt udvalg af farver og designs, så du nemt kan finde et par, der passer perfekt til din personlige stil.': 1,\n",
+ " 'de bedste ballerina sko kendetegnes ved deres komfort og støtte.': 1,\n",
+ " 'de skal have en fleksibel, men stabil sål, der giver god affjedring og støtte til foden.': 1,\n",
+ " 'materialet bør være blødt og åndbart, så foden kan bevæge sig frit uden at blive irriteret.': 1,\n",
+ " 'desuden er det vigtigt, at skoen passer perfekt til foden og ikke glider eller gnaver.': 1,\n",
+ " 'hvis du leder efter de bedste ballerina sko, anbefaler vi at du køber de bedste ballerina sko online.': 1,\n",
+ " 'her finder du et stort udvalg af kvalitetssko, der lever op til disse krav.': 1,\n",
+ " 'det er vigtigt at finde den rette størrelse og pasform, når du køber ballerina sko online.': 1,\n",
+ " 'måling af foden er nøglen til at finde den perfekte størrelse.': 1,\n",
+ " 'brug en lineal til at måle længden og bredden af din fod, og sammenlign målingerne med størrelsesguiden fra den webshop, du køber fra.': 1,\n",
+ " 'nogle webshops tilbyder også muligheden for at gemme dine mål, så du nemt kan finde den rette størrelse næste gang.': 1,\n",
+ " 'derudover er det en god idé at kigge på anmeldelser af skoenes pasform, så du ved, om de falder lille eller stor i størrelsen.': 1,\n",
+ " 'hvis du er i tvivl, kan du også overveje at købe smykkeskrin med ballerina i mange varianter, så du kan prøve flere størrelser.': 1,\n",
+ " 'ballerina sko fremstilles typisk af forskellige materialer, som hver især tilbyder forskellige fordele.': 1,\n",
+ " 'nogle af de mest populære materialer inkluderer: læder – et klassisk og holdbart materiale, som giver god støtte og pasform.': 1,\n",
+ " 'lædersko er ofte mere kostbare, men kan holde i mange år.': 1,\n",
+ " 'kanvas – et let og åndbart materiale, der er ideelt til dansere, der laver mange bevægelser.': 1,\n",
+ " 'kanvas sko er ofte mere overkommelige i pris.': 1,\n",
+ " 'satin – et elegant og feminint materiale, som giver en flot finish på sko.': 1,\n",
+ " 'satin sko er dog mindre holdbare end læder- og kanvasmodeller.': 1,\n",
+ " 'uanset hvilket materiale du vælger, er det vigtigt at finde sko, der passer godt og føles komfortable at have på.': 1,\n",
+ " 'det er den bedste måde at sikre, at dine ballerina sko holder i lang tid.': 1,\n",
+ " 'ballerina sko er et alsidigt valg, der kan bæres til mange forskellige lejligheder.': 1,\n",
+ " 'uanset om du skal til en uformel sammenkomst, en mere formel begivenhed eller blot ønsker at se stilfuld ud til hverdag, findes der ballerina sko, der passer perfekt.': 1,\n",
+ " 'de flade sko er komfortable at gå i hele dagen og giver et elegant, feminint udtryk.': 1,\n",
+ " 'vælg mellem forskellige materialer, farver og detaljer for at finde det rette par, der matcher din personlige stil og påklædning.': 1,\n",
+ " 'pleje og vedligeholdelse af dine ballerina sko er vigtig for at sikre, at de holder længe og ser pæne ud.': 1,\n",
+ " 'rengør dine sko regelmæssigt med en blød børste og et mildt rengøringsmiddel.': 1,\n",
+ " 'undgå at bruge for meget vand, da det kan beskadige materialet.': 1,\n",
+ " 'lad dine sko lufttørre i stedet for at bruge en tørretumbler.': 1,\n",
+ " 'opbevar dine sko i deres originale æske eller en anden beskyttende emballage, når de ikke er i brug.': 1,\n",
+ " 'dette hjælper med at bevare formen og forhindrer, at de bliver beskadiget.': 1,\n",
+ " 'følg også producentens anvisninger for pleje og vedligeholdelse, da forskellige materialer kan kræve forskellige metoder.': 1,\n",
+ " 'ballerina sko kommer i et bredt udvalg af stilarter og trends.': 1,\n",
+ " 'de klassiske ballerina sko med flad hæl og afrundet tå er stadig populære, men der er også kommet flere moderne varianter på markedet.': 1,\n",
+ " 'nogle har en lidt højere hæl eller en mere spids tå for et mere elegant udtryk.': 1,\n",
+ " 'andre har ekstra detaljer som sløjfer, bånd eller perlebesætninger for et mere feminint look.': 1,\n",
+ " 'uanset om du foretrækker et klassisk eller et mere trendy design, er der sikkert et par ballerina sko, der passer perfekt til din personlige stil.': 1,\n",
+ " 'ballerina sko er ikke kun et stilfuldt og elegant valg, men også et bæredygtigt alternativ.': 1,\n",
+ " 'mange producenter fokuserer i stigende grad på at fremstille sko med miljøvenlige materialer og produktionsprocesser.': 1,\n",
+ " ...})"
+ ]
+ },
+ "execution_count": 753,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "new_sents = total_sent_count - previous_counter\n",
+ "new_sents"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import json"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data_loaded = {}\n",
+ "for file in os.listdir(\"report_data\"):\n",
+ " with open(os.path.join(\"report_data\", file), \"r\", encoding=\"utf-8\") as f:\n",
+ " data_loaded[file] = json.load(f)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['da-crawl-19_06_24_06_56_30.json', 'da-crawl-19_06_24_12_11_15.json', 'da-crawl-19_06_24_14_14_52.json', 'da-crawl-20_06_24_05_52_55.json', 'de-crawl-19_06_24_07_19_27.json', 'de-crawl-19_06_24_12_33_29.json', 'de-crawl-20_06_24_06_03_42.json', 'en-crawl-19_06_24_08_17_02.json', 'en-crawl-20_06_24_08_58_37.json', 'es-crawl-18_06_24_10_46_20.json', 'es-crawl-20_06_24_10_43_21.json', 'fr-crawl-19_06_24_07_16_52.json', 'fr-crawl-19_06_24_12_25_43.json', 'fr-crawl-20_06_24_09_46_58.json', 'nl-crawl-19_06_24_10_04_31.json', 'nl-crawl-20_06_24_08_42_14.json'])"
+ ]
+ },
+ "execution_count": 756,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data_loaded.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'82': {'article_data': {'sents_removed': {},\n",
+ " 'topics_counter': {'Culture': 3}},\n",
+ " 'last_crawled_time': '2024-06-19 06:51:25.256570',\n",
+ " 'repeated_articles': 7,\n",
+ " 'total_articles': 10,\n",
+ " 'total_downloaded': 3,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 13.71},\n",
+ " '135': {'article_data': {},\n",
+ " 'total_articles': 0,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 0,\n",
+ " 'crawl_time': 1.4},\n",
+ " '136': {'article_data': {'sents_removed': {'Der er ikke oplæsning af denne artikel, så den oplæses derfor med maskinstemme.': 1,\n",
+ " 'Kontakt os gerne på automatiskoplaesning@pol.dk, hvis du hører ord, hvis udtale kan forbedres.': 1,\n",
+ " '\\n Læs artiklen senere\\n Gemt (klik for at fjerne)\\n Læst': 2,\n",
+ " '\\n FOR ABONNENTER': 2,\n",
+ " 'Prøv Politiken nu': 1},\n",
+ " 'topics_counter': {'Politics': 16, 'Culture': 2, 'Health': 1, 'Sport': 2},\n",
+ " 'quality_error': {'TOO_SHORT': 4}},\n",
+ " 'last_crawled_time': '2024-06-19 06:51:40.222930',\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 16,\n",
+ " 'total_low_quality': 4,\n",
+ " 'total_in_db': 0,\n",
+ " 'crawl_time': 56.35},\n",
+ " '139': {'article_data': {'sents_removed': {},\n",
+ " 'topics_counter': {'Culture': 1}},\n",
+ " 'last_crawled_time': '2024-06-19 06:52:36.344905',\n",
+ " 'repeated_articles': 16,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 1,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 5.48},\n",
+ " '140': {'article_data': {'sents_removed': {},\n",
+ " 'topics_counter': {'Sport': 1, 'Culture': 1}},\n",
+ " 'last_crawled_time': '2024-06-19 06:52:41.863117',\n",
+ " 'repeated_articles': 13,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 7,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 12.21},\n",
+ " '141': {'article_data': {'sents_removed': {},\n",
+ " 'topics_counter': {'Politics': 4}},\n",
+ " 'last_crawled_time': '2024-06-19 06:52:54.066308',\n",
+ " 'repeated_articles': 15,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 4,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 8.82},\n",
+ " '142': {'article_data': {'sents_removed': {}, 'topics_counter': {}},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:02.894014',\n",
+ " 'repeated_articles': 17,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 2,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 6.29},\n",
+ " '143': {'article_data': {'sents_removed': {},\n",
+ " 'topics_counter': {'Politics': 3},\n",
+ " 'quality_error': {'TOO_SHORT': 1}},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:09.193252',\n",
+ " 'repeated_articles': 14,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 3,\n",
+ " 'total_low_quality': 1,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 18.0},\n",
+ " '144': {'article_data': {},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:27.194445',\n",
+ " 'repeated_articles': 20,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 1.25},\n",
+ " '145': {'article_data': {'sents_removed': {},\n",
+ " 'quality_error': {'TOO_SHORT': 3},\n",
+ " 'topics_counter': {'Sport': 5}},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:28.550842',\n",
+ " 'repeated_articles': 5,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 5,\n",
+ " 'total_low_quality': 3,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 28.28},\n",
+ " '146': {'article_data': {'sents_removed': {}, 'topics_counter': {}},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:56.737203',\n",
+ " 'repeated_articles': 19,\n",
+ " 'total_articles': 20,\n",
+ " 'total_downloaded': 1,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 2.24},\n",
+ " '147': {'article_data': {'sents_removed': {},\n",
+ " 'quality_error': {'TOO_SHORT': 7}},\n",
+ " 'last_crawled_time': '2024-06-19 06:53:59.724658',\n",
+ " 'repeated_articles': 3,\n",
+ " 'total_articles': 10,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 7,\n",
+ " 'total_in_db': 0,\n",
+ " 'crawl_time': 31.24},\n",
+ " '148': {'article_data': {'sents_removed': {},\n",
+ " 'quality_error': {'TOO_SHORT': 1}},\n",
+ " 'last_crawled_time': '2024-06-19 06:54:30.263863',\n",
+ " 'repeated_articles': 9,\n",
+ " 'total_articles': 10,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 1,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 2.92},\n",
+ " '149': {'article_data': {'sents_removed': {'Dit medlemskab giver adgang': 1,\n",
+ " 'Som medlem af IDA har du gratis adgang til PLUS-indhold, som en del af dit medlemskab.': 1,\n",
+ " 'Fortsæt med MitIDA for at aktivere din adgang til indholdet.': 1,\n",
+ " 'Oplever du problemer med login, så skriv til os på websupport@ing.dk': 1,\n",
+ " 'Abonnementsfordele': 1,\n",
+ " 'vpn_key': 1,\n",
+ " 'Fuld adgang til Ing.dk, Version2 og Radar': 1,\n",
+ " 'Fuld digital adgang til PLUS-indhold på Ing.dk, Version2 og Radar, tilgængeligt på din computer, tablet og mobil.': 1,\n",
+ " 'drafts': 1,\n",
+ " 'Kuraterede nyhedsbreve': 1,\n",
+ " 'Det seneste nye fra branchen, leveret til din indbakke.': 1,\n",
+ " 'thumb_up': 1,\n",
+ " 'Adgang til debatten': 1,\n",
+ " 'Deltag i debatten med andre kloge læsere.': 1},\n",
+ " 'quality_error': {'ML_PREDICTION': 41}},\n",
+ " 'last_crawled_time': '2024-06-19 06:54:33.171093',\n",
+ " 'repeated_articles': 4,\n",
+ " 'total_articles': 50,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 41,\n",
+ " 'total_in_db': 0,\n",
+ " 'crawl_time': 100.22},\n",
+ " '150': {'article_data': {},\n",
+ " 'last_crawled_time': '2024-06-19 06:56:13.319234',\n",
+ " 'repeated_articles': 10,\n",
+ " 'total_articles': 10,\n",
+ " 'total_downloaded': 0,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 1,\n",
+ " 'crawl_time': 0.71},\n",
+ " '160': {'article_data': {'sents_removed': {'Mad': 1, 'Varme': 1},\n",
+ " 'topics_counter': {'Health': 1, 'Culture': 1}},\n",
+ " 'last_crawled_time': '2024-06-19 06:56:20.301303',\n",
+ " 'total_articles': 5,\n",
+ " 'total_downloaded': 5,\n",
+ " 'total_low_quality': 0,\n",
+ " 'total_in_db': 0,\n",
+ " 'crawl_time': 16.9}}"
+ ]
+ },
+ "execution_count": 763,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data_loaded['da-crawl-19_06_24_06_56_30.json'][\"feeds\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from collections import Counter\n",
+ "\n",
+ "def accumulate_date_for_language(lang, loaded_data):\n",
+ " accumulated_dict = {}\n",
+ " accumulated_dict[\"feeds\"] = {}\n",
+ " for key in loaded_data.keys():\n",
+ " current_dict = loaded_data[key]\n",
+ " if lang in key:\n",
+ " print(f\"Reading... '{key}'\")\n",
+ " accumulated_dict[\"total_time\"] = accumulated_dict.get(\"total_time\", []) + [current_dict[\"total_time\"]]\n",
+ " accumulated_dict[\"date\"] = accumulated_dict.get(\"date\", []) + [key.split(\"-\")[-1]]\n",
+ " for feed in current_dict[\"feeds\"].keys():\n",
+ " if feed not in accumulated_dict[\"feeds\"]:\n",
+ " accumulated_dict[\"feeds\"][feed] = {}\n",
+ " for key, val in current_dict[\"feeds\"][feed].items():\n",
+ " if key == \"article_data\":\n",
+ " if key not in accumulated_dict[\"feeds\"][feed]:\n",
+ " accumulated_dict[\"feeds\"][feed][key] = {}\n",
+ " for art_key, art_val in current_dict[\"feeds\"][feed][\"article_data\"].items():\n",
+ " accumulated_dict[\"feeds\"][feed][key][art_key] = Counter(accumulated_dict[\"feeds\"][feed].get(key, {}).get(art_key, {})) + Counter(art_val)\n",
+ " else:\n",
+ " accumulated_dict[\"feeds\"][feed][key] = accumulated_dict[\"feeds\"][feed].get(key, []) + [val]\n",
+ " return accumulated_dict\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['feeds', 'total_time'])"
+ ]
+ },
+ "execution_count": 810,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data_loaded['da-crawl-19_06_24_06_56_30.json'].keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Reading... 'da-crawl-19_06_24_06_56_30.json'\n",
+ "Reading... 'da-crawl-19_06_24_12_11_15.json'\n",
+ "Reading... 'da-crawl-19_06_24_14_14_52.json'\n",
+ "Reading... 'da-crawl-20_06_24_05_52_55.json'\n",
+ "Reading... 'de-crawl-19_06_24_07_19_27.json'\n",
+ "Reading... 'de-crawl-19_06_24_12_33_29.json'\n",
+ "Reading... 'de-crawl-20_06_24_06_03_42.json'\n",
+ "Reading... 'en-crawl-19_06_24_08_17_02.json'\n",
+ "Reading... 'en-crawl-20_06_24_08_58_37.json'\n",
+ "Reading... 'es-crawl-18_06_24_10_46_20.json'\n",
+ "Reading... 'es-crawl-20_06_24_10_43_21.json'\n",
+ "Reading... 'fr-crawl-19_06_24_07_16_52.json'\n",
+ "Reading... 'fr-crawl-19_06_24_12_25_43.json'\n",
+ "Reading... 'fr-crawl-20_06_24_09_46_58.json'\n",
+ "Reading... 'nl-crawl-19_06_24_10_04_31.json'\n",
+ "Reading... 'nl-crawl-20_06_24_08_42_14.json'\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc_dict = accumulate_date_for_language(\"\", data_loaded)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['82', '135', '136', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '160', '161', '4', '15', '71', '76', '123', '124', '92', '94', '96', '97', '102', '103', '109', '110', '111', '112', '113', '114', '115', '122', '126', '127', '128', '129', '75', '95', '101', '104', '59', '60', '61', '66', '80', '83', '84', '107', '108', '130', '159', '41', '46', '50', '85', '87', '88', '89', '91', '125'])"
+ ]
+ },
+ "execution_count": 818,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc_dict[\"feeds\"].keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'82': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Culture': 8})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:51:25.256570',\n",
+ " '2024-06-19 12:06:36.600204',\n",
+ " '2024-06-19 14:03:18.854455',\n",
+ " '2024-06-20 05:43:01.907458'],\n",
+ " 'repeated_articles': [7, 7, 10, 8],\n",
+ " 'total_articles': [10, 10, 10, 10],\n",
+ " 'total_downloaded': [3, 3, 0, 2],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [13.71, 13.47, 0.94, 14.99]},\n",
+ " '135': {'article_data': {},\n",
+ " 'total_articles': [0, 0, 0, 0],\n",
+ " 'total_downloaded': [0, 0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [0, 0, 0, 0],\n",
+ " 'crawl_time': [1.4, 1.43, 1.31, 1.64]},\n",
+ " '136': {'article_data': {'sents_removed': Counter({'\\n Læs artiklen senere\\n Gemt (klik for at fjerne)\\n Læst': 4,\n",
+ " '\\n FOR ABONNENTER': 4,\n",
+ " 'Der er ikke oplæsning af denne artikel, så den oplæses derfor med maskinstemme.': 2,\n",
+ " 'Kontakt os gerne på automatiskoplaesning@pol.dk, hvis du hører ord, hvis udtale kan forbedres.': 2,\n",
+ " 'Prøv Politiken nu': 2,\n",
+ " 'ritzau': 1,\n",
+ " 'Ritzau': 1}),\n",
+ " 'topics_counter': Counter({'Politics': 53,\n",
+ " 'Sport': 8,\n",
+ " 'Culture': 7,\n",
+ " 'Health': 4,\n",
+ " 'Music': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 11})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:51:40.222930',\n",
+ " '2024-06-19 12:06:51.345036',\n",
+ " '2024-06-19 14:03:20.939978',\n",
+ " '2024-06-20 05:43:18.377774'],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [16, 15, 6, 16],\n",
+ " 'total_low_quality': [4, 1, 2, 4],\n",
+ " 'total_in_db': [0, 0, 1, 0],\n",
+ " 'crawl_time': [56.35, 47.24, 24.99, 65.28],\n",
+ " 'repeated_articles': [4, 12]},\n",
+ " '139': {'article_data': {'sents_removed': Counter({'- Ja.': 1}),\n",
+ " 'topics_counter': Counter({'Culture': 4, 'Music': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:52:36.344905',\n",
+ " '2024-06-19 12:07:38.527206',\n",
+ " '2024-06-19 14:03:45.842252',\n",
+ " '2024-06-20 05:44:23.372029'],\n",
+ " 'repeated_articles': [16, 16, 16, 16],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [1, 1, 1, 1],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [5.48, 6.02, 6.08, 6.07]},\n",
+ " '140': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Sport': 1,\n",
+ " 'Culture': 1,\n",
+ " 'Business': 1,\n",
+ " 'Health': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 3})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:52:41.863117',\n",
+ " '2024-06-19 12:07:44.562914',\n",
+ " '2024-06-19 14:03:52.279412',\n",
+ " '2024-06-20 05:44:29.465087'],\n",
+ " 'repeated_articles': [13, 16, 18, 14],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [7, 3, 1, 4],\n",
+ " 'total_low_quality': [0, 1, 1, 1],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [12.21, 7.84, 5.1, 12.41]},\n",
+ " '141': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Politics': 13, 'Sport': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:52:54.066308',\n",
+ " '2024-06-19 12:07:52.394247',\n",
+ " '2024-06-19 14:03:57.071103',\n",
+ " '2024-06-20 05:44:41.853593'],\n",
+ " 'repeated_articles': [15, 15, 19, 13],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [4, 4, 0, 6],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 0],\n",
+ " 'crawl_time': [8.82, 8.96, 2.94, 11.61]},\n",
+ " '142': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Business': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:02.894014',\n",
+ " '2024-06-19 12:08:02.260896',\n",
+ " '2024-06-19 14:04:00.400019',\n",
+ " '2024-06-20 05:44:53.483734'],\n",
+ " 'repeated_articles': [17, 19, 18, 18],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [2, 0, 1, 1],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [6.29, 3.49, 5.44, 4.34]},\n",
+ " '143': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Politics': 8}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 4})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:09.193252',\n",
+ " '2024-06-19 12:08:04.839745',\n",
+ " '2024-06-19 14:04:06.072983',\n",
+ " '2024-06-20 05:44:57.843591'],\n",
+ " 'repeated_articles': [14, 15, 17, 15],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [3, 2, 0, 3],\n",
+ " 'total_low_quality': [1, 1, 1, 1],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [18.0, 10.91, 8.02, 9.28]},\n",
+ " '144': {'article_data': {},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:27.194445',\n",
+ " '2024-06-19 12:08:15.715680',\n",
+ " '2024-06-19 14:04:13.432911',\n",
+ " '2024-06-20 05:45:07.046888'],\n",
+ " 'repeated_articles': [20, 20, 20, 20],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [0, 0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [1.25, 0.75, 0.84, 0.83]},\n",
+ " '145': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 11}),\n",
+ " 'topics_counter': Counter({'Sport': 21})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:28.550842',\n",
+ " '2024-06-19 12:08:16.521008',\n",
+ " '2024-06-19 14:04:14.319144',\n",
+ " '2024-06-20 05:45:07.923743'],\n",
+ " 'repeated_articles': [5, 6, 6, 2],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [5, 3, 3, 10],\n",
+ " 'total_low_quality': [3, 3, 2, 3],\n",
+ " 'total_in_db': [1, 1, 0, 1],\n",
+ " 'crawl_time': [28.28, 20.4, 29.82, 29.42]},\n",
+ " '146': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:56.737203',\n",
+ " '2024-06-19 12:08:36.953031',\n",
+ " '2024-06-19 14:04:44.147944',\n",
+ " '2024-06-20 05:45:37.338226'],\n",
+ " 'repeated_articles': [19, 20, 19, 19],\n",
+ " 'total_articles': [20, 20, 20, 20],\n",
+ " 'total_downloaded': [1, 0, 1, 1],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [2.24, 0.83, 2.84, 2.33]},\n",
+ " '147': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 28})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:53:59.724658',\n",
+ " '2024-06-19 12:08:38.500996',\n",
+ " '2024-06-19 14:04:48.294122',\n",
+ " '2024-06-20 05:45:40.727370'],\n",
+ " 'repeated_articles': [3, 3, 3, 3],\n",
+ " 'total_articles': [10, 10, 10, 10],\n",
+ " 'total_downloaded': [0, 0, 0, 0],\n",
+ " 'total_low_quality': [7, 7, 7, 7],\n",
+ " 'total_in_db': [0, 0, 0, 0],\n",
+ " 'crawl_time': [31.24, 35.55, 33.9, 46.39]},\n",
+ " '148': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 4}),\n",
+ " 'topics_counter': Counter({'Politics': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:54:30.263863',\n",
+ " '2024-06-19 12:09:13.604226',\n",
+ " '2024-06-19 14:05:20.899356',\n",
+ " '2024-06-20 05:46:26.093489'],\n",
+ " 'repeated_articles': [9, 8, 9, 9],\n",
+ " 'total_articles': [10, 10, 10, 10],\n",
+ " 'total_downloaded': [0, 1, 0, 0],\n",
+ " 'total_low_quality': [1, 1, 1, 1],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [2.92, 4.94, 2.9, 3.0]},\n",
+ " '149': {'article_data': {'sents_removed': Counter({'Abonnementsfordele': 4,\n",
+ " 'vpn_key': 4,\n",
+ " 'drafts': 4,\n",
+ " 'Kuraterede nyhedsbreve': 4,\n",
+ " 'thumb_up': 4,\n",
+ " 'Adgang til debatten': 4,\n",
+ " 'Dit medlemskab giver adgang': 3,\n",
+ " 'Som medlem af IDA har du gratis adgang til PLUS-indhold, som en del af dit medlemskab.': 3,\n",
+ " 'Fortsæt med MitIDA for at aktivere din adgang til indholdet.': 3,\n",
+ " 'Oplever du problemer med login, så skriv til os på websupport@ing.dk': 3,\n",
+ " 'Fuld adgang til Ing.dk, Version2 og Radar': 3,\n",
+ " 'Fuld digital adgang til PLUS-indhold på Ing.dk, Version2 og Radar, tilgængeligt på din computer, tablet og mobil.': 3,\n",
+ " 'Det seneste nye fra branchen, leveret til din indbakke.': 3,\n",
+ " 'Deltag i debatten med andre kloge læsere.': 3}),\n",
+ " 'quality_error': Counter({'ML_PREDICTION': 165, 'TOO_SHORT': 3}),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 06:54:33.171093',\n",
+ " '2024-06-19 12:09:18.275395',\n",
+ " '2024-06-19 14:05:24.803248',\n",
+ " '2024-06-20 05:46:29.116153'],\n",
+ " 'repeated_articles': [4, 2, 3, 3],\n",
+ " 'total_articles': [50, 50, 50, 50],\n",
+ " 'total_downloaded': [0, 1, 1, 1],\n",
+ " 'total_low_quality': [41, 43, 42, 42],\n",
+ " 'total_in_db': [0, 0, 1, 0],\n",
+ " 'crawl_time': [100.22, 108.23, 104.77, 104.22]},\n",
+ " '150': {'article_data': {},\n",
+ " 'last_crawled_time': ['2024-06-19 06:56:13.319234',\n",
+ " '2024-06-19 12:11:06.453810',\n",
+ " '2024-06-19 14:07:08.534293',\n",
+ " '2024-06-20 05:48:13.271704'],\n",
+ " 'repeated_articles': [10, 10, 10, 10],\n",
+ " 'total_articles': [10, 10, 10, 10],\n",
+ " 'total_downloaded': [0, 0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1, 1],\n",
+ " 'crawl_time': [0.71, 0.73, 0.67, 0.72]},\n",
+ " '160': {'article_data': {'sents_removed': Counter({'Mad': 1, 'Varme': 1}),\n",
+ " 'topics_counter': Counter({'Culture': 5, 'Health': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 06:56:20.301303',\n",
+ " '2024-06-19 12:11:11.163457',\n",
+ " '2024-06-19 14:07:12.664112',\n",
+ " '2024-06-20 05:48:18.674272'],\n",
+ " 'total_articles': [5, 2, 1, 3],\n",
+ " 'total_downloaded': [5, 2, 1, 3],\n",
+ " 'total_low_quality': [0, 0, 0, 0],\n",
+ " 'total_in_db': [0, 0, 0, 0],\n",
+ " 'crawl_time': [16.9, 9.05, 6.35, 12.02]},\n",
+ " '161': {'article_data': {'sents_removed': Counter({'/ritzau/': 2}),\n",
+ " 'topics_counter': Counter({'Politics': 29,\n",
+ " 'Sport': 25,\n",
+ " 'Culture': 24,\n",
+ " 'Business': 4,\n",
+ " 'Health': 2}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 26})},\n",
+ " 'last_crawled_time': ['2024-06-19 14:14:08', '2024-06-20 05:51:04'],\n",
+ " 'repeated_articles': [3],\n",
+ " 'total_articles': [129, 77],\n",
+ " 'total_downloaded': [92, 62],\n",
+ " 'total_low_quality': [20, 6],\n",
+ " 'total_in_db': [1, 0],\n",
+ " 'crawl_time': [457.86, 270.53]},\n",
+ " '4': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Sport': 3,\n",
+ " 'Culture': 3,\n",
+ " 'Business': 3,\n",
+ " 'Politics': 2,\n",
+ " 'Food': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 21})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:16:19.837760',\n",
+ " '2024-06-19 12:30:39.142406',\n",
+ " '2024-06-20 05:59:51.013755'],\n",
+ " 'repeated_articles': [1, 12, 1],\n",
+ " 'total_articles': [36, 43, 41],\n",
+ " 'total_downloaded': [13, 2, 13],\n",
+ " 'total_low_quality': [6, 7, 8],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [87.54, 79.37, 102.78]},\n",
+ " '15': {'article_data': {},\n",
+ " 'total_articles': [0, 0, 0],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [1.32, 1.3, 1.26]},\n",
+ " '71': {'article_data': {'sents_removed': Counter({'Podcast': 6,\n",
+ " 'Bücher': 6,\n",
+ " 'Coaching': 6,\n",
+ " 'Artikel': 6,\n",
+ " 'Über mich': 6,\n",
+ " 'Kontakt': 6,\n",
+ " 'Home': 3,\n",
+ " '\\n\\t\\t\\t\\t': 3,\n",
+ " '\\t\\t\\t\\t': 3,\n",
+ " '\\nHome': 3}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 78})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:17:50.213737',\n",
+ " '2024-06-19 12:32:01.338372',\n",
+ " '2024-06-20 06:01:36.461062'],\n",
+ " 'repeated_articles': [34, 34, 34],\n",
+ " 'total_articles': [60, 60, 60],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [26, 26, 26],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [56.04, 56.48, 85.46]},\n",
+ " '76': {'article_data': {'sents_removed': Counter({' Externer Inhalt von Youtube': 1,\n",
+ " ' Um externe Inhalte anzuzeigen, ist Ihre widerrufliche Zustimmung nötig.': 1,\n",
+ " 'Dabei können personenbezogene Daten von Drittplattformen (ggf.': 1,\n",
+ " 'USA) verarbeitet werden.': 1,\n",
+ " 'Weitere Informationen .': 1,\n",
+ " 'TickarooLive Blog Software': 1}),\n",
+ " 'topics_counter': Counter({'Politics': 12,\n",
+ " 'Sport': 11,\n",
+ " 'Business': 4,\n",
+ " 'Food': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 16})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:18:44.792620',\n",
+ " '2024-06-19 12:32:56.243373',\n",
+ " '2024-06-20 06:03:00.287162'],\n",
+ " 'repeated_articles': [1, 7],\n",
+ " 'total_articles': [19, 21, 18],\n",
+ " 'total_downloaded': [13, 7, 14],\n",
+ " 'total_low_quality': [5, 7, 4],\n",
+ " 'total_in_db': [1, 0, 0],\n",
+ " 'crawl_time': [41.79, 31.55, 41.22]},\n",
+ " '123': {'article_data': {},\n",
+ " 'last_crawled_time': ['2024-06-19 07:19:26.844387',\n",
+ " '2024-06-19 12:33:28.120204',\n",
+ " '2024-06-20 06:03:41.857455'],\n",
+ " 'repeated_articles': [12, 12, 12],\n",
+ " 'total_articles': [12, 12, 12],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [1.16, 1.21, 1.16]},\n",
+ " '124': {'article_data': {},\n",
+ " 'total_articles': [0, 0, 0],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [0.88, 1.19, 0.75]},\n",
+ " '92': {'article_data': {'sents_removed': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 08:11:44.982147',\n",
+ " '2024-06-20 08:52:46.709914'],\n",
+ " 'repeated_articles': [3, 3],\n",
+ " 'feed_error': ['This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/v5/images/20240416-KAHN-Tech-Project-0208_maxWidth_3000_maxHeight_3000_ppi_72_quality_95_embedColorProfile_true_2024-06-17-142805_shee.jpg?crop=focalpoint&fit=crop&fp-x=0.5&fp-y=0.5&h=630&imgixProfile=propublicaAssetsV5&q=90&w=1200&s=08075b9ee4a3a21850b24d020fb7173f\\', \\'domain_name_id\\': 1377}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)',\n",
+ " 'This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/v5/images/20240416-KAHN-Tech-Project-0208_maxWidth_3000_maxHeight_3000_ppi_72_quality_95_embedColorProfile_true_2024-06-17-142805_shee.jpg?crop=focalpoint&fit=crop&fp-x=0.5&fp-y=0.5&h=630&imgixProfile=propublicaAssetsV5&q=90&w=1200&s=08075b9ee4a3a21850b24d020fb7173f\\', \\'domain_name_id\\': 1377}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)']},\n",
+ " '94': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Social Sciences': 3,\n",
+ " 'Culture': 2,\n",
+ " 'Food': 1,\n",
+ " 'Politics': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:11:52.356495',\n",
+ " '2024-06-20 08:52:50.687479'],\n",
+ " 'repeated_articles': [44, 49],\n",
+ " 'total_articles': [50, 50],\n",
+ " 'total_downloaded': [6, 1],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [18.43, 4.08]},\n",
+ " '96': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [0.83, 0.79]},\n",
+ " '97': {'article_data': {'sents_removed': Counter({'PROVERBS': 2}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 13}),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 08:12:08.886953',\n",
+ " '2024-06-20 08:52:57.488594'],\n",
+ " 'repeated_articles': [3, 3],\n",
+ " 'total_articles': [10, 10],\n",
+ " 'total_downloaded': [0, 1],\n",
+ " 'total_low_quality': [7, 6],\n",
+ " 'total_in_db': [0, 1],\n",
+ " 'crawl_time': [23.64, 27.88]},\n",
+ " '102': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 33}),\n",
+ " 'topics_counter': Counter({'Satire': 4, 'Food': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:12:32.146713',\n",
+ " '2024-06-20 08:53:23.592295'],\n",
+ " 'repeated_articles': [33, 30],\n",
+ " 'total_articles': [50, 50],\n",
+ " 'total_downloaded': [1, 3],\n",
+ " 'total_low_quality': [16, 17],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [33.57, 40.31]},\n",
+ " '103': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Food': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:13:05.608168',\n",
+ " '2024-06-20 08:54:03.705470'],\n",
+ " 'repeated_articles': [46, 38],\n",
+ " 'total_articles': [50, 50],\n",
+ " 'total_downloaded': [4, 12],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [9.11, 25.1]},\n",
+ " '109': {'article_data': {'sents_removed': Counter({' ': 8,\n",
+ " ' ': 6,\n",
+ " ' \\n ': 6,\n",
+ " '\\n ': 2,\n",
+ " '\\n Explore the latest news, articles and features': 2,\n",
+ " 'View introductory offers': 1,\n",
+ " 'No commitment, cancel anytime*': 1,\n",
+ " '*Cancel anytime within 14 days of payment to receive a refund on unserved issues.': 1,\n",
+ " 'Inclusive of applicable taxes (VAT)': 1,\n",
+ " 'or': 1,\n",
+ " 'Existing subscribers': 1,\n",
+ " 'Sign in to your account': 1}),\n",
+ " 'topics_counter': Counter({'Science': 14, 'Social Sciences': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:13:14.938268',\n",
+ " '2024-06-20 08:54:28.926975'],\n",
+ " 'repeated_articles': [95, 91],\n",
+ " 'total_articles': [100, 100],\n",
+ " 'total_downloaded': [5, 9],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [11.68, 19.62]},\n",
+ " '110': {'article_data': {'sents_removed': Counter({'1': 2,\n",
+ " '2': 2,\n",
+ " '3': 2,\n",
+ " '4': 2,\n",
+ " '5': 2,\n",
+ " ' X': 2,\n",
+ " ' Facebook': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:13:26.427706',\n",
+ " '2024-06-20 08:54:48.448551'],\n",
+ " 'feed_error': ['This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/img/media/2b7eb67907743d9d3ce2c038083d5d958262cd92/133_0_6554_3934/master/6554.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctZGVmYXVsdC5wbmc&enable=upscale&s=f8280a5f433f51cf31767d0e15ae0e4f\\', \\'domain_name_id\\': 1383}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)',\n",
+ " 'This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/img/media/a324fcc1dd29b9bba1bde123f2a7def0c599b142/132_0_6555_3934/master/6555.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctZGVmYXVsdC5wbmc&enable=upscale&s=c6cb274ad002c92989bae69acb9e18a8\\', \\'domain_name_id\\': 1383}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)']},\n",
+ " '111': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [1.05, 1.04]},\n",
+ " '112': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [1.09, 1.04]},\n",
+ " '113': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 26}),\n",
+ " 'topics_counter': Counter({'Sport': 15,\n",
+ " 'Food': 5,\n",
+ " 'Social Sciences': 4,\n",
+ " 'Health': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:13:31.828134',\n",
+ " '2024-06-20 08:54:53.315947'],\n",
+ " 'repeated_articles': [39, 29],\n",
+ " 'total_articles': [89, 79],\n",
+ " 'total_downloaded': [36, 38],\n",
+ " 'total_low_quality': [14, 12],\n",
+ " 'total_in_db': [1, 0],\n",
+ " 'crawl_time': [94.95, 98.7]},\n",
+ " '114': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 08:15:06.989892',\n",
+ " '2024-06-20 08:56:32.285198'],\n",
+ " 'repeated_articles': [7, 7],\n",
+ " 'total_articles': [8, 8],\n",
+ " 'total_downloaded': [1, 1],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [8.75, 8.96]},\n",
+ " '115': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 08:15:15.184730',\n",
+ " '2024-06-20 08:56:40.826928'],\n",
+ " 'total_articles': [69, 69],\n",
+ " 'total_downloaded': [0, 1],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [88.24, 93.74]},\n",
+ " '122': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-19 08:16:44.093608',\n",
+ " '2024-06-20 08:58:15.055674'],\n",
+ " 'repeated_articles': [20, 19],\n",
+ " 'total_articles': [20, 20],\n",
+ " 'total_downloaded': [0, 1],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [1.36, 3.76]},\n",
+ " '126': {'article_data': {'sents_removed': Counter({'Post': 6,\n",
+ " 'Share': 3,\n",
+ " 'Annotate': 3,\n",
+ " 'Save': 3,\n",
+ " 'Print': 3,\n",
+ " '\\n\\t\\t': 1}),\n",
+ " 'topics_counter': Counter({'Business': 8}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:16:44.727223',\n",
+ " '2024-06-20 08:58:18.239347'],\n",
+ " 'repeated_articles': [20, 20],\n",
+ " 'total_articles': [25, 25],\n",
+ " 'total_downloaded': [4, 4],\n",
+ " 'total_low_quality': [1, 1],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [12.91, 14.21]},\n",
+ " '127': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [0.75, 0.68]},\n",
+ " '128': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [0.63, 1.03]},\n",
+ " '129': {'article_data': {'sents_removed': Counter({'2h ago': 6,\n",
+ " '1h ago': 2,\n",
+ " '3h ago': 2,\n",
+ " '8m ago': 1,\n",
+ " '22m ago': 1,\n",
+ " '47m ago': 1,\n",
+ " '4m ago': 1,\n",
+ " '10m ago': 1,\n",
+ " '48m ago': 1,\n",
+ " 'It adds:': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 08:16:59.359685',\n",
+ " '2024-06-20 08:58:34.441997'],\n",
+ " 'feed_error': ['This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/img/media/995e1dbf452a9076169927f7c9ef3a39e5c861de/0_200_6000_3600/master/6000.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctbGl2ZS5wbmc&enable=upscale&s=6db4555580d0c0396c58606c9dbb88e7\\', \\'domain_name_id\\': 1383}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)',\n",
+ " 'This Session\\'s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (pymysql.err.DataError) (1406, \"Data too long for column \\'path\\' at row 1\")\\n[SQL: INSERT INTO url (title, path, domain_name_id) VALUES (%(title)s, %(path)s, %(domain_name_id)s)]\\n[parameters: {\\'title\\': \\'\\', \\'path\\': \\'/img/media/d0b34ea15a3b6fbed4d3df8796ac2c31727d83fc/0_161_3315_1989/master/3315.jpg?width=1200&height=630&quality=85&auto=format&fit=crop&overlay-align=bottom%2Cleft&overlay-width=100p&overlay-base64=L2ltZy9zdGF0aWMvb3ZlcmxheXMvdGctbGl2ZS5wbmc&enable=upscale&s=a05f9f8b4c00228f927343572fc46396\\', \\'domain_name_id\\': 1383}]\\n(Background on this error at: https://sqlalche.me/e/20/9h9h) (Background on this error at: https://sqlalche.me/e/20/7s2a)']},\n",
+ " '75': {'article_data': {'sents_removed': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-18 10:46:05.303661',\n",
+ " '2024-06-20 10:42:33.271221'],\n",
+ " 'repeated_articles': [18, 18],\n",
+ " 'total_articles': [21, 21],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [3.48, 3.1]},\n",
+ " '95': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [2.09, 1.61]},\n",
+ " '101': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [1.41, 1.87]},\n",
+ " '104': {'article_data': {'sents_removed': Counter(),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 4}),\n",
+ " 'topics_counter': Counter()},\n",
+ " 'last_crawled_time': ['2024-06-18 10:46:12.851700',\n",
+ " '2024-06-20 10:42:40.302246'],\n",
+ " 'repeated_articles': [52, 34],\n",
+ " 'total_articles': [55, 55],\n",
+ " 'total_downloaded': [1, 19],\n",
+ " 'total_low_quality': [2, 2],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [8.37, 42.04]},\n",
+ " '59': {'article_data': {'sents_removed': Counter({'La rédaction vous conseille': 2}),\n",
+ " 'quality_error': Counter({'HTML_PATTERN': 45}),\n",
+ " 'topics_counter': Counter({'Health': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:11:25.120451',\n",
+ " '2024-06-19 12:23:13.687212',\n",
+ " '2024-06-20 09:41:37.210677'],\n",
+ " 'repeated_articles': [4, 5, 4],\n",
+ " 'total_articles': [20, 20, 20],\n",
+ " 'total_downloaded': [1, 0, 1],\n",
+ " 'total_low_quality': [15, 15, 15],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [34.94, 28.03, 30.47]},\n",
+ " '60': {'article_data': {'sents_removed': Counter({'La rédaction vous conseille': 1,\n",
+ " 'Rome': 1}),\n",
+ " 'quality_error': Counter({'HTML_PATTERN': 21}),\n",
+ " 'topics_counter': Counter({'Culture': 5,\n",
+ " 'Travel': 3,\n",
+ " 'Music': 1,\n",
+ " 'Sport': 1,\n",
+ " 'Science': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:11:59.913157',\n",
+ " '2024-06-19 12:23:41.689386',\n",
+ " '2024-06-20 09:42:07.544327'],\n",
+ " 'total_articles': [20, 20, 20],\n",
+ " 'total_downloaded': [9, 1, 13],\n",
+ " 'total_low_quality': [11, 3, 7],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [35.08, 8.38, 35.64],\n",
+ " 'repeated_articles': [16]},\n",
+ " '61': {'article_data': {},\n",
+ " 'total_articles': [0, 0, 0],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [0.72, 0.73, 0.81]},\n",
+ " '66': {'article_data': {'sents_removed': Counter({'Se connecter': 3,\n",
+ " 'Lecture restreinte': 2,\n",
+ " 'Votre abonnement n’autorise pas la lecture de cet article': 2,\n",
+ " 'Pour plus d’informations, merci de contacter notre service commercial.': 2}),\n",
+ " 'quality_error': Counter({'HTML_PATTERN': 56, 'TOO_SHORT': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:12:35.698139',\n",
+ " '2024-06-19 12:23:50.737609',\n",
+ " '2024-06-20 09:42:43.993879'],\n",
+ " 'total_articles': [19, 19, 19],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [19, 19, 19],\n",
+ " 'total_in_db': [0, 0, 0],\n",
+ " 'crawl_time': [36.16, 35.44, 35.45]},\n",
+ " '80': {'article_data': {'sents_removed': Counter({' ma liste': 3,\n",
+ " ' réagir': 3,\n",
+ " '\\n Les commentaires sont soumis à des règles de modération.': 3,\n",
+ " 'lire la charte': 3,\n",
+ " '\\n Il n’y a pas encore de commentaire à cet article.': 3,\n",
+ " '\\n Pas le temps de lire cet article ?': 2,\n",
+ " 'Découvrez la lecture audio.': 2}),\n",
+ " 'topics_counter': Counter({'Sport': 91, 'World': 1, 'Travel': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 16})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:13:11.868851',\n",
+ " '2024-06-19 12:24:26.250027',\n",
+ " '2024-06-20 09:43:19.386482'],\n",
+ " 'total_articles': [50, 50, 50],\n",
+ " 'total_downloaded': [46, 3, 42],\n",
+ " 'total_low_quality': [4, 4, 8],\n",
+ " 'total_in_db': [0, 1, 0],\n",
+ " 'crawl_time': [96.39, 15.85, 96.45],\n",
+ " 'repeated_articles': [43]},\n",
+ " '83': {'article_data': {'sents_removed': Counter({'Correct !': 3,\n",
+ " 'Faux !': 3,\n",
+ " '\\t\\t\\t': 1,\n",
+ " 'Facebook': 1,\n",
+ " '\\n\\t\\t': 1}),\n",
+ " 'topics_counter': Counter({'Culture': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:14:50.463959',\n",
+ " '2024-06-19 12:24:45.198937',\n",
+ " '2024-06-20 09:44:57.344422'],\n",
+ " 'repeated_articles': [9, 10, 10],\n",
+ " 'total_articles': [10, 10, 10],\n",
+ " 'total_downloaded': [1, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [5.44, 3.89, 2.27]},\n",
+ " '84': {'article_data': {'sents_removed': Counter({'Article abonné': 2,\n",
+ " '\\n': 1}),\n",
+ " 'topics_counter': Counter({'Politics': 10,\n",
+ " 'Culture': 5,\n",
+ " 'Health': 2,\n",
+ " 'Science': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:14:53.704332',\n",
+ " '2024-06-19 12:24:46.297932',\n",
+ " '2024-06-20 09:44:58.115731'],\n",
+ " 'repeated_articles': [5, 20, 2],\n",
+ " 'total_articles': [20, 20, 20],\n",
+ " 'total_downloaded': [15, 0, 18],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [26.7, 1.22, 32.54]},\n",
+ " '107': {'article_data': {},\n",
+ " 'last_crawled_time': ['2024-06-19 07:15:19.936103',\n",
+ " '2024-06-19 12:24:46.719656',\n",
+ " '2024-06-20 09:45:30.297870'],\n",
+ " 'repeated_articles': [25, 25, 25],\n",
+ " 'total_articles': [27, 27, 27],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [2.08, 1.97, 2.06]},\n",
+ " '108': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Politics': 19,\n",
+ " 'Science': 9,\n",
+ " 'Health': 8,\n",
+ " 'Technology': 2,\n",
+ " 'Culture': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 6})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:15:23.003805',\n",
+ " '2024-06-19 12:24:50.074785',\n",
+ " '2024-06-20 09:45:33.328280'],\n",
+ " 'repeated_articles': [74, 90, 76],\n",
+ " 'total_articles': [100, 100, 100],\n",
+ " 'total_downloaded': [25, 8, 21],\n",
+ " 'total_low_quality': [1, 2, 3],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [53.44, 23.01, 49.1]},\n",
+ " '130': {'article_data': {},\n",
+ " 'last_crawled_time': ['2024-06-19 07:16:15.420725',\n",
+ " '2024-06-19 12:25:11.694385',\n",
+ " '2024-06-20 09:46:21.349799'],\n",
+ " 'total_articles': [1, 1, 1],\n",
+ " 'total_downloaded': [0, 0, 0],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [1, 1, 1],\n",
+ " 'crawl_time': [0.23, 0.21, 0.22]},\n",
+ " '159': {'article_data': {'sents_removed': Counter({'À voir également sur Le HuffPost': 3}),\n",
+ " 'topics_counter': Counter({'Politics': 19,\n",
+ " 'Culture': 7,\n",
+ " 'Sport': 7,\n",
+ " 'World': 7,\n",
+ " 'Science': 2,\n",
+ " 'Health': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 07:16:16.130207',\n",
+ " '2024-06-19 12:25:12.544584',\n",
+ " '2024-06-20 09:46:22.187633'],\n",
+ " 'total_articles': [20, 20, 20],\n",
+ " 'total_downloaded': [20, 17, 20],\n",
+ " 'total_low_quality': [0, 0, 0],\n",
+ " 'total_in_db': [0, 1, 0],\n",
+ " 'crawl_time': [37.21, 31.86, 36.98],\n",
+ " 'repeated_articles': [3]},\n",
+ " '41': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Culture': 4,\n",
+ " 'Sport': 2,\n",
+ " 'Food': 2,\n",
+ " 'Politics': 1,\n",
+ " 'Business': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 10})},\n",
+ " 'last_crawled_time': ['2024-06-19 09:57:05.598984',\n",
+ " '2024-06-20 08:35:28.650162'],\n",
+ " 'total_articles': [38, 38],\n",
+ " 'total_downloaded': [16, 0],\n",
+ " 'total_low_quality': [10, 0],\n",
+ " 'total_in_db': [0, 1],\n",
+ " 'crawl_time': [63.72, 43.03],\n",
+ " 'repeated_articles': [1]},\n",
+ " '46': {'article_data': {'sents_removed': Counter({'Geselecteerd door de redactie': 2,\n",
+ " '6 vragen': 1,\n",
+ " 'Analyse': 1}),\n",
+ " 'topics_counter': Counter({'Culture': 4,\n",
+ " 'Food': 2,\n",
+ " 'Business': 1,\n",
+ " 'Science': 1,\n",
+ " 'Politics': 1,\n",
+ " 'Sport': 1,\n",
+ " 'Technology': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 09:58:09.393651',\n",
+ " '2024-06-20 08:36:11.824177'],\n",
+ " 'repeated_articles': [4, 11],\n",
+ " 'total_articles': [19, 18],\n",
+ " 'total_downloaded': [15, 6],\n",
+ " 'total_low_quality': [0, 1],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [27.7, 14.16]},\n",
+ " '50': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [0.87, 0.7]},\n",
+ " '85': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Sport': 5,\n",
+ " 'Food': 4,\n",
+ " 'Politics': 4,\n",
+ " 'Science': 1,\n",
+ " 'Culture': 1,\n",
+ " 'Travel': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 09:58:37.857602',\n",
+ " '2024-06-20 08:36:26.605355'],\n",
+ " 'repeated_articles': [2, 5],\n",
+ " 'total_articles': [20, 20],\n",
+ " 'total_downloaded': [18, 15],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [32.57, 26.81]},\n",
+ " '87': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Food': 7,\n",
+ " 'Sport': 4,\n",
+ " 'Science': 2,\n",
+ " 'Politics': 2,\n",
+ " 'Business': 2,\n",
+ " 'Culture': 1}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 166})},\n",
+ " 'last_crawled_time': ['2024-06-19 09:59:12.570318',\n",
+ " '2024-06-20 08:36:55.422122'],\n",
+ " 'repeated_articles': [2736, 2640],\n",
+ " 'total_articles': [2874, 2777],\n",
+ " 'total_downloaded': [52, 49],\n",
+ " 'total_low_quality': [82, 84],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [282.8, 283.71]},\n",
+ " '88': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [1.61, 1.36]},\n",
+ " '89': {'article_data': {'sents_removed': Counter(),\n",
+ " 'topics_counter': Counter({'Food': 1})},\n",
+ " 'last_crawled_time': ['2024-06-19 10:03:55.269844',\n",
+ " '2024-06-20 08:41:39.367778'],\n",
+ " 'total_articles': [20, 20],\n",
+ " 'total_downloaded': [20, 20],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [31.82, 30.42]},\n",
+ " '91': {'article_data': {},\n",
+ " 'total_articles': [0, 0],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [0, 0],\n",
+ " 'total_in_db': [0, 0],\n",
+ " 'crawl_time': [1.57, 1.78]},\n",
+ " '125': {'article_data': {'sents_removed': Counter({'Follow': 2, '--': 2}),\n",
+ " 'quality_error': Counter({'TOO_SHORT': 2})},\n",
+ " 'last_crawled_time': ['2024-06-19 10:04:28.329321',\n",
+ " '2024-06-20 08:42:10.695650'],\n",
+ " 'repeated_articles': [2, 2],\n",
+ " 'total_articles': [3, 3],\n",
+ " 'total_downloaded': [0, 0],\n",
+ " 'total_low_quality': [1, 1],\n",
+ " 'total_in_db': [1, 1],\n",
+ " 'crawl_time': [4.14, 4.5]}}"
+ ]
+ },
+ "execution_count": 819,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc_dict[\"feeds\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_total_quality_counts(acc_dict):\n",
+ " total_counts = Counter()\n",
+ " for feed in acc_dict[\"feeds\"]:\n",
+ " if \"article_data\" not in acc_dict[\"feeds\"][feed]:\n",
+ " continue\n",
+ " if \"quality_error\" not in acc_dict[\"feeds\"][feed][\"article_data\"]:\n",
+ " continue\n",
+ " total_counts += Counter(acc_dict[\"feeds\"][feed][\"article_data\"][\"quality_error\"])\n",
+ " return total_counts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "total_rejected_article_reasons = dict(get_total_quality_counts(acc_dict))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "total_rejected_article_reasons\n",
+ "total_rejected_article_reasons[\"Total\"] = sum(total_rejected_article_reasons.values())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "pd_quality_errors = pd.DataFrame.from_dict(total_rejected_article_reasons, orient=\"index\").reset_index()\n",
+ "pd_quality_errors.columns = [\"Reason\", \"Count\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ " \n",
+ " \n",
+ " Reason \n",
+ " Count \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " TOO_SHORT \n",
+ " 485 \n",
+ " \n",
+ " \n",
+ " ML_PREDICTION \n",
+ " 165 \n",
+ " \n",
+ " \n",
+ " HTML_PATTERN \n",
+ " 122 \n",
+ " \n",
+ " \n",
+ " Total \n",
+ " 772 \n",
+ " \n",
+ " \n",
+ "
\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(pd_quality_errors.to_html(index=False))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 685,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "previous_counter = total_sent_count"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "topicExtract",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.18"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tools/report_generator/generate_report.py b/tools/report_generator/generate_report.py
new file mode 100644
index 00000000..d1eddf3e
--- /dev/null
+++ b/tools/report_generator/generate_report.py
@@ -0,0 +1,627 @@
+import pandas as pd
+import matplotlib.pyplot as plt
+from matplotlib import rcParams
+from tools.crawl_summary.crawl_report import CrawlReport
+import seaborn as sns
+from data_extractor import DataExtractor
+from sqlalchemy import create_engine
+import datetime
+import os
+import argparse
+import pathlib
+from collections import Counter
+from tqdm import tqdm
+from nltk.tokenize import sent_tokenize
+
+FOLDER_FOR_REPORT_OUTPUT = os.environ.get(
+ "FOLDER_FOR_REPORT_OUTPUT",
+ os.path.join(pathlib.Path(__file__).parent.resolve(), "reports"),
+)
+
+
+def set_legend_to_right_side(ax):
+ # https://stackoverflow.com/questions/4700614/how-to-put-the-legend-outside-the-plot
+ box = ax.get_position()
+ ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
+ ax.legend(loc="center left", bbox_to_anchor=(1, 0.5))
+
+
+def get_color_palette(n_items):
+ if n_items <= 10:
+ return sns.color_palette("tab10")
+ else:
+ return sns.color_palette("tab20")
+
+
+def identify_repeating_patterns(article_df, sents_filtered_set: set):
+ def normalize_sent(text: str):
+ return text.lower().strip()
+
+ def sent_count(text: str):
+ return Counter(
+ [
+ normalize_sent(sent)
+ for paragraph in text.split("\n\n")
+ for sent in sent_tokenize(paragraph)
+ if len(sent.strip()) > 10
+ ]
+ )
+
+ def get_total_sent_counts(text_list: list[str]):
+ total_counts = Counter()
+ for text in tqdm(text_list, total=len(text_list)):
+ total_counts += sent_count(text)
+ return total_counts
+
+ print("Evaluating new repeating patterns...")
+ total_counts = get_total_sent_counts(article_df.content)
+ sents_occur_more_than_10 = [
+ [sent, count]
+ for sent, count in total_counts.items()
+ if count > 10 and sent not in sents_filtered_set
+ ]
+ return pd.DataFrame(sents_occur_more_than_10, columns=["Sent", "Count"])
+
+
+def save_fig_params(filename):
+ if not os.path.exists(FOLDER_FOR_REPORT_OUTPUT):
+ os.mkdir(FOLDER_FOR_REPORT_OUTPUT)
+ img_folder = os.path.join(FOLDER_FOR_REPORT_OUTPUT, "img")
+ if not os.path.exists(img_folder):
+ os.mkdir(img_folder)
+ path_to_img = os.path.join(img_folder, filename)
+ rel_path = os.path.join("img", filename)
+ plt.savefig(path_to_img, bbox_inches="tight")
+ plt.clf()
+ return rel_path
+
+
+def get_new_repeating_sents(pd_repeating_sents):
+ return generate_html_table(pd_repeating_sents.sort_values("Count", ascending=False))
+
+
+def get_rejected_sentences_table(total_deleted_sents):
+ total_deleted_sents["Total"] = sum(total_deleted_sents.values())
+ pd_deleted_sents = pd.DataFrame.from_dict(
+ total_deleted_sents, orient="index"
+ ).reset_index()
+ pd_deleted_sents.columns = ["Reason", "Count"]
+ return generate_html_table(pd_deleted_sents.sort_values("Count", ascending=False))
+
+
+def get_total_reject_article_reason_table(total_rejected_article_reasons):
+ total_rejected_article_reasons["Total"] = sum(
+ total_rejected_article_reasons.values()
+ )
+ pd_quality_errors = pd.DataFrame.from_dict(
+ total_rejected_article_reasons, orient="index"
+ ).reset_index()
+ pd_quality_errors.columns = ["Reason", "Count"]
+ return generate_html_table(pd_quality_errors.sort_values("Count", ascending=True))
+
+
+def generate_feed_count_plots(feed_df, lang):
+ filename = f"feed_downloaded_articles_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if feed_df[feed_df["Language"] == lang].Count.sum() == 0:
+ return ""
+ plt.figure(lang)
+ sns.barplot(
+ x="Feed Name",
+ y="Count",
+ hue="Feed Name",
+ data=feed_df[feed_df["Language"] == lang],
+ )
+ plt.title(lang)
+ plt.xticks(rotation=35, ha="right")
+ return save_fig_params(filename)
+
+
+def generate_bookmarks_by_language_plot(boomark_df):
+ filename = f"bookmarks_plot_{date_str}_d{DAYS_FOR_REPORT}.png"
+ bookmark_plot = (
+ boomark_df.groupby(["Language", "Has Exercised"])[["user_id"]]
+ .count()
+ .reset_index()
+ .rename(columns={"user_id": "Count"})
+ )
+ sns.barplot(data=bookmark_plot, x="Language", y="Count", hue="Has Exercised")
+ plt.title("Total Bookmarks by Language")
+ plt.xticks(rotation=35, ha="right")
+ return save_fig_params(filename)
+
+
+def generate_topic_by_feed_plot(article_topic_df, lang):
+ # If I want to make topics consistant
+ # https://stackoverflow.com/questions/39000115/how-can-i-set-the-colors-per-value-when-coloring-plots-by-a-dataframe-column
+ filename = f"topics_per_feed_lang_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ topic_monitor = (
+ article_topic_df.groupby(["Language", "Feed Name"])
+ .Topic.value_counts()
+ .reset_index()
+ )
+ total_sources = len(
+ topic_monitor[topic_monitor["Language"] == lang]["Feed Name"].unique()
+ )
+
+ ax = plt.subplot(111)
+ sns.barplot(
+ x="Topic",
+ y="count",
+ hue="Feed Name",
+ data=topic_monitor[topic_monitor["Language"] == lang],
+ palette=get_color_palette(total_sources),
+ )
+ set_legend_to_right_side(ax)
+ plt.title(f"{lang} - Topic Report")
+ plt.xlabel("Topic")
+ plt.xticks(rotation=35, ha="right")
+ return save_fig_params(filename)
+
+
+def generate_topic_coverage_plot(article_df, article_with_topics_df):
+ filename = f"topic_coverage_plot_{date_str}_d{DAYS_FOR_REPORT}.png"
+ article_df["has_topic"] = "No"
+ article_df.loc[article_df.id.isin(article_with_topics_df.id), "has_topic"] = "Yes"
+ articles_with_topics = (
+ article_df.groupby("Language")
+ .has_topic.value_counts(normalize=True)
+ .reset_index()
+ )
+ sns.barplot(
+ x="Language",
+ y="proportion",
+ hue="has_topic",
+ data=articles_with_topics,
+ palette=[sns.color_palette("vlag")[0], sns.color_palette("vlag")[5]],
+ )
+ plt.title("Proportion of Articles with Topics")
+ plt.xticks(rotation=35, ha="right")
+ return save_fig_params(filename)
+
+
+def generate_total_article_per_language(article_df):
+ filename = f"total_articles_downloaded_{date_str}_d{DAYS_FOR_REPORT}.png"
+ data = article_df["Language"].value_counts().reset_index()
+ sns.barplot(
+ x="Language",
+ y="count",
+ hue="Language",
+ data=data,
+ palette=get_color_palette(len(data["Language"].unique())),
+ )
+ plt.title("New Articles Downloaded")
+ plt.xticks(rotation=35, ha="right")
+ plt.ylabel("Total Articles")
+ return save_fig_params(filename)
+
+
+def generate_histogram(article_df, column, bins=20, remove_outliers=False):
+ filename = (
+ f"hist_{column}_removed_out_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if remove_outliers
+ else f"hist_{column}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ )
+ if remove_outliers:
+ article_df[article_df[column] < article_df[column].quantile(0.99)].groupby(
+ "Language"
+ )[column].plot.hist(alpha=0.5, bins=bins)
+ else:
+ article_df.groupby("Language")[column].plot.hist(alpha=0.5, bins=bins)
+ plt.title(f"{column} Distribution")
+ plt.legend()
+ return save_fig_params(filename)
+
+
+def generate_user_reading_time(user_reading_time_df, lang=""):
+ filename = (
+ f"user_reading_time_plot_all_lang_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if lang == ""
+ else f"user_reading_time_plot_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ )
+ plot_total_reading_time = (
+ user_reading_time_df.groupby(["Language", "Feed Name"])
+ .total_reading_time.sum()
+ .reset_index()
+ .sort_values("Feed Name")
+ )
+ if lang == "":
+ sns.barplot(
+ x="Language",
+ y="total_reading_time",
+ hue="Language",
+ data=plot_total_reading_time,
+ )
+ plt.title("Total Reading Time by users per Language")
+ else:
+ sns.barplot(
+ x="Feed Name",
+ y="total_reading_time",
+ hue="Feed Name",
+ data=plot_total_reading_time[plot_total_reading_time["Language"] == lang],
+ )
+ plt.title(f"{lang} - Total Reading time by users per Feed")
+ plt.xticks(rotation=35, ha="right")
+ plt.ylabel("Total Reading time (mins)")
+ return save_fig_params(filename)
+
+
+def generate_unique_articles_read_plot(user_reading_time_df, lang=""):
+ filename = (
+ f"user_unique_articles_read_plot_all_lang_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if lang == ""
+ else f"user_unique_articles_read_plot_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ )
+
+ if lang == "":
+ plot_unique_articles_read = (
+ user_reading_time_df.Language.value_counts().reset_index()
+ )
+ sns.barplot(
+ x="Language",
+ y="count",
+ hue="Language",
+ data=plot_unique_articles_read,
+ )
+ plt.title("Total Unique Articles Opened by users per Language")
+ else:
+ plot_unique_articles_read = (
+ user_reading_time_df.groupby(["Language"])["Feed Name"]
+ .value_counts()
+ .reset_index()
+ .sort_values("Feed Name")
+ )
+ print(plot_unique_articles_read)
+ sns.barplot(
+ x="Feed Name",
+ y="count",
+ hue="Feed Name",
+ data=plot_unique_articles_read[
+ plot_unique_articles_read["Language"] == lang
+ ],
+ )
+ plt.title(f"{lang} - Total Unique Articles Opened by users per Feed")
+ plt.xticks(rotation=35, ha="right")
+ plt.ylabel("Total Opened Article Count")
+ return save_fig_params(filename)
+
+
+def generate_topic_reading_time(topic_reading_time_df, lang=""):
+ filename = (
+ f"topic_reading_time_plot_all_lang_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if lang == ""
+ else f"topic_reading_time_plot_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ )
+ plot_total_reading_time = (
+ topic_reading_time_df.groupby(["Language", "Topic"])
+ .total_reading_time.sum()
+ .reset_index()
+ )
+ if lang == "":
+ ax = plt.subplot(111)
+ sns.barplot(
+ x="Language",
+ y="total_reading_time",
+ hue="Topic",
+ data=plot_total_reading_time,
+ palette=get_color_palette(len(plot_total_reading_time["Topic"].unique())),
+ )
+ set_legend_to_right_side(ax)
+ plt.title("Total Reading Time by Topic per Language")
+ else:
+ sns.barplot(
+ x="Topic",
+ y="total_reading_time",
+ hue="Topic",
+ data=plot_total_reading_time[plot_total_reading_time["Language"] == lang],
+ )
+ plt.title(f"{lang} - Total Reading time by Topic")
+ plt.xticks(rotation=35, ha="right")
+ plt.ylabel("Total Reading time (mins)")
+ return save_fig_params(filename)
+
+
+def generate_exercise_activity(exercise_activity_df, lang=""):
+ filename = (
+ f"exercise_activity_plot_all_lang_{date_str}_d{DAYS_FOR_REPORT}.png"
+ if lang == ""
+ else f"exercise_activity_plot_{lang}_{date_str}_d{DAYS_FOR_REPORT}.png"
+ )
+ ax = plt.subplot(111)
+ if lang == "":
+ sns.barplot(
+ x="Source",
+ y="total_exercises",
+ hue="Language",
+ data=exercise_activity_df,
+ )
+ plt.title("Total Exercises Performed by Language")
+ set_legend_to_right_side(ax)
+ else:
+ sns.barplot(
+ x="Source",
+ y="total_exercises",
+ hue="Source",
+ data=exercise_activity_df[exercise_activity_df["Language"] == lang],
+ )
+ plt.title(f"{lang} - Total Exercses Performed by Type")
+
+ plt.xticks(rotation=35, ha="right")
+ plt.ylabel("Total Exercises Count")
+ return save_fig_params(filename)
+
+
+def print_descriptive_stats(df, title, precision=2):
+ print(f"############## {title} Descriptive Stats ##############")
+ print(df.describe().round(precision).to_string())
+
+
+def generate_html_table(df, round_precision=2):
+ return (
+ df.round(round_precision)
+ .to_html(index=False)
+ .replace('class="dataframe"', 'class="pure-table"')
+ )
+
+
+def generate_active_users_table(active_user_read_ex_pd, bookmark_pd):
+ reading_time_ex_time = (
+ active_user_read_ex_pd.groupby("Language")[
+ ["total_exercise_time", "total_reading_time"]
+ ]
+ .sum()
+ .reset_index()
+ )
+ reading_time_ex_time["Count"] = (
+ active_user_read_ex_pd.groupby("Language")[["user_id"]]
+ .count()
+ .reset_index()["user_id"]
+ )
+
+ bookmark_count = (
+ bookmark_pd.groupby(["Language"])["user_id"]
+ .describe()["count"]
+ .reset_index()
+ .rename(columns={"count": "Total Bookmarks"})
+ )
+ bookmark_review_proportion = (
+ bookmark_pd.groupby(["Language"])["Has Exercised"]
+ .value_counts(normalize=True)
+ .reset_index()
+ .rename(columns={"proportion": "Bookmarks % Reviewed"})
+ )
+ bookmark_review_proportion = bookmark_review_proportion[
+ bookmark_review_proportion["Has Exercised"] == "Yes"
+ ]
+ if len(bookmark_count) > 0:
+ reading_time_ex_time = reading_time_ex_time.merge(
+ bookmark_review_proportion, on="Language", how="inner"
+ )
+
+ reading_time_ex_time = reading_time_ex_time.merge(
+ bookmark_count, on="Language", how="inner"
+ )
+ else:
+ reading_time_ex_time["Bookmarks % Reviewed"] = 0
+ reading_time_ex_time["Total Bookmarks"] = 0
+
+ return generate_html_table(
+ reading_time_ex_time[
+ [
+ "Language",
+ "Count",
+ "total_exercise_time",
+ "total_reading_time",
+ "Bookmarks % Reviewed",
+ "Total Bookmarks",
+ ]
+ ]
+ )
+
+
+def generate_top_opened_articles(user_reading_time_df, article_df):
+ top_5_articles_by_opened = (
+ user_reading_time_df.groupby(["Language", "Feed Name"])
+ .id.value_counts()
+ .reset_index()
+ .sort_values("count", ascending=False)[:5]
+ )
+ print(top_5_articles_by_opened)
+ top_5_articles_by_opened = top_5_articles_by_opened.merge(
+ article_df[["id", "title"]], on="id"
+ )[["Language", "Feed Name", "id", "title", "count"]]
+ print(top_5_articles_by_opened)
+ top_5_articles_by_opened = top_5_articles_by_opened.rename(
+ columns={"id": "Article id", "title": "Article Title", "count": "Users Count"}
+ )
+ return generate_html_table(top_5_articles_by_opened)
+
+
+def generate_html_page():
+ data_extractor = DataExtractor(db_connection, DAYS_FOR_REPORT)
+
+ feed_df = data_extractor.get_feed_df()
+ article_df = data_extractor.get_article_df(feed_df)
+ article_topics_df = data_extractor.get_article_topics_df(feed_df)
+ language_df = data_extractor.get_language_df()
+ bookmark_df = data_extractor.get_bookmark_df()
+ data_extractor.add_stats_to_feed(feed_df, article_df)
+ user_reading_time_df = data_extractor.get_user_reading_activity(
+ language_df, feed_df
+ )
+ user_exercise_time_df = data_extractor.get_user_exercise_activity()
+ combined_user_activity_df = (
+ data_extractor.get_combined_user_reading_exercise_activity(
+ user_exercise_time_df, user_reading_time_df
+ )
+ )
+ topic_reading_time_df = data_extractor.get_topic_reading_time()
+ total_unique_articles_opened_by_users = len(
+ article_df[article_df.id.isin(user_reading_time_df.id)]
+ )
+ exercise_activity_df = data_extractor.get_exercise_type_activity()
+ crawl_report = CrawlReport()
+ crawl_report.load_crawl_report_data(DAYS_FOR_REPORT)
+ total_days_from_crawl_report = crawl_report.get_days_from_crawl_report_date()
+ print("############ Report date: ", crawl_report.crawl_report_date)
+ total_removed_sents = crawl_report.get_total_removed_sents_counts()
+ if DAYS_FOR_REPORT <= 7:
+ pd_new_repeated_sents = identify_repeating_patterns(
+ article_df, set(total_removed_sents.keys())
+ )
+ warning_crawl_range = (
+ ""
+ if total_days_from_crawl_report == DAYS_FOR_REPORT
+ else f"WARNING! This date only contains values from the last '{total_days_from_crawl_report}' day(s)."
+ )
+ ACTIVE_USER_ACTIVITY_TIME_MIN = 1
+ articles_with_topic_count = len(article_topics_df.id.unique())
+ active_users = combined_user_activity_df[
+ (
+ combined_user_activity_df["total_reading_time"]
+ > ACTIVE_USER_ACTIVITY_TIME_MIN
+ )
+ | (
+ combined_user_activity_df["total_exercise_time"]
+ > ACTIVE_USER_ACTIVITY_TIME_MIN
+ )
+ ]
+ total_active_users = len(active_users)
+ lang_report = ""
+ for lang in article_df["Language"].unique():
+ lang_report += f"""
+ {lang}
+ Articles Downloaded
+
+
+ User Activity
+ """
+ if lang in active_users["Language"].values:
+ lang_report += f"""
+ Total Active users : {len(active_users[active_users["Language"] == lang])}
+
+
+
+
+
+ """
+ else:
+ lang_report += """
+ No active users in this language
+
+ """
+ lang_links = ""
+
+ for lang in article_df["Language"].unique():
+ lang_links += f"""
+ {lang}
+ """
+ lang_links += " "
+ title = (
+ f"""Week Report Nr {CURRENT_WEEK_N}"""
+ if DAYS_FOR_REPORT == 7
+ else f"Last {DAYS_FOR_REPORT} days Report"
+ )
+ result = f"""
+
+
+
+
+ {title}
+ Generated at: {datetime.datetime.now(tz=datetime.timezone.utc)} UTC
+
+ Total Articles Crawled: {len(article_df)}
+ Total Unique Articles Opened: {total_unique_articles_opened_by_users}
+
Topic Coverage: {((articles_with_topic_count / len(article_df)) * 100) if len(article_df) > 0 else 0:.2f}%
+
+
+
+ Articles Rejected:
+ {warning_crawl_range}
+ {get_total_reject_article_reason_table(crawl_report.get_total_non_quality_counts())}
+ Word Count:
+ {generate_html_table(article_df.groupby("Language").word_count.describe().reset_index())}
+ FK Difficulty:
+ {generate_html_table(article_df.groupby("Language").fk_difficulty.describe().reset_index())}
+ Activity Report
+ Total Active Users: {total_active_users}
+ """
+ if total_active_users == 0:
+ result += """No active users in this period
+ """
+ else:
+ result += f"""
+ Top Articles Read:
+ {generate_active_users_table(combined_user_activity_df, bookmark_df)}
+
+ {generate_top_opened_articles(user_reading_time_df, article_df)}
+
+
+
+
+ """
+ result += f"""
+ Removed Sents Table
+
Per Language Report:
+ {lang_links}
+
+ {lang_report}
+
+ Newly identified repeating patterns:
+ Sentences that occur in more than 10 articles during this weeks crawl, and were not filtered.
+ {get_new_repeating_sents(pd_new_repeated_sents) if DAYS_FOR_REPORT <= 7 else "
Skipped due to long period.
"}
+ Removed Article Sents:
+ {warning_crawl_range}
+ {get_rejected_sentences_table(total_removed_sents)}
+
+ """
+ with open(
+ os.path.join(
+ FOLDER_FOR_REPORT_OUTPUT,
+ f"report_zeeguu_{date_str}_d{DAYS_FOR_REPORT}.html",
+ ),
+ "w",
+ encoding="UTF-8",
+ ) as f:
+ f.write(result)
+
+ return result
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser("generate_plots_report")
+ parser.add_argument(
+ "number_of_days",
+ nargs="?",
+ default=7,
+ help="Number of days from the current date that will be cnsidered for the report.",
+ type=int,
+ )
+ args = parser.parse_args()
+ DAYS_FOR_REPORT = args.number_of_days
+ print(
+ f"## Reporting for the last {DAYS_FOR_REPORT} days, today is: {datetime.datetime.now()}"
+ )
+ print(
+ "################################################################################"
+ )
+ from zeeguu.api.app import create_app
+
+ app = create_app()
+ sns.set_theme("paper", "whitegrid")
+ cur_time = datetime.datetime.now()
+ CURRENT_WEEK_N = max(cur_time.isocalendar()[1] - 1, 1)
+ date_str = cur_time.strftime("%Y_%m_%d")
+
+ DB_URI = app.config["SQLALCHEMY_DATABASE_URI"]
+ # rcParams["figure.figsize"] = 10, 8
+ db_connection = create_engine(
+ DB_URI,
+ pool_recycle=300,
+ connect_args={"connect_timeout": 300, "read_timeout": 600},
+ )
+ generate_html_page()
diff --git a/zeeguu/core/content_cleaning/__init__.py b/zeeguu/core/content_cleaning/__init__.py
index 71645403..aaf88cc9 100644
--- a/zeeguu/core/content_cleaning/__init__.py
+++ b/zeeguu/core/content_cleaning/__init__.py
@@ -1,4 +1,7 @@
-from zeeguu.core.content_cleaning.content_cleaner import cleanup_non_content_bits
+from zeeguu.core.content_cleaning.content_cleaner import (
+ cleanup_non_content_bits,
+ cleanup_non_content_bits_w_crawl_report,
+)
from zeeguu.core.content_cleaning.unicode_normalization import (
flatten_composed_unicode_characters,
)
@@ -7,3 +10,8 @@
def cleanup_text(text):
result = cleanup_non_content_bits(text)
return flatten_composed_unicode_characters(result)
+
+
+def cleanup_text_w_crawl_report(text, crawl_report, feed, url):
+ result = cleanup_non_content_bits_w_crawl_report(text, crawl_report, feed, url)
+ return flatten_composed_unicode_characters(result)
diff --git a/zeeguu/core/content_cleaning/content_cleaner.py b/zeeguu/core/content_cleaning/content_cleaner.py
index 36740cdc..ae348bcc 100644
--- a/zeeguu/core/content_cleaning/content_cleaner.py
+++ b/zeeguu/core/content_cleaning/content_cleaner.py
@@ -1,5 +1,6 @@
import zeeguu.core
from zeeguu.core.model import Article, Language
+from nltk.tokenize import sent_tokenize
JUNK_PATTERNS_TO_REMOVE = [
"\nAdvertisement\n",
@@ -21,9 +22,1087 @@
"Lecture restreinte",
"Pour plus d’informations, merci de contacter notre service commercial.",
# dk
- "Artiklen fortsætter efter annoncen"
+ "Artiklen fortsætter efter annoncen",
]
+JUNK_COUNT_PATTERNS = (
+ [
+ # DA Articles
+ "artiklen er opdateret kl.",
+ "for abonnenter",
+ "det skriver nyhedsbureauet afp.",
+ "det skriver nyhedsbureauet reuters.",
+ "opdateres ...",
+ "artiklen fortsætter under billedet …",
+ "der er ikke oplæsning af denne artikel, så den oplæses derfor med maskinstemme.",
+ "kontakt os gerne på automatiskoplaesning@pol.dk, hvis du hører ord, hvis udtale kan forbedres.",
+ "du kan også hjælpe ved at udfylde spørgeskemaet herunder, hvor vi spørger, hvordan du har oplevet den automatiske oplæsning.",
+ "spørgeskema om automatisk oplæsning",
+ "prøv politiken nu",
+ "mere fra os",
+ "allerede abonnent?",
+ "log ind her",
+ "du skal være abonnent for at lytte til denne automatiske oplæsning.",
+ "køb abonnement",
+ "ruslands angreb på ukraine",
+ "artiklen fortsætter efter annoncen",
+ "(foto: © mads claus rasmussen, ritzau scanpix)",
+ "foto: jens dresling",
+ "ruslands invasion af ukraine",
+ "efter længere tids massiv troppeopbygning angreb rusland ukraine torsdag 24. februar 2022.",
+ "en række ukrainske byer blev bombet samtidig med, at russiske soldater trængte ind i ukraine fra syd, øst og nord.",
+ "artiklen fortsætter under henvisningen …",
+ "hundredvis!",
+ "i samfundets varetægt",
+ "du har ingen artikler på din læseliste",
+ "hvis du ser en artikel, du gerne vil læse lidt senere, kan du klikke på dette ikon",
+ "så bliver artiklen føjet til din læseliste, som du altid kan finde her, så du kan læse videre hvor du vil og når du vil.",
+ "se alle ulæste",
+ "se alt du følger",
+ "sådan fungerer læselisten",
+ "udvælg de artikler, der interesserer dig, og opbyg din egen læseliste.",
+ "så har du altid et sted at starte, når du har tid til at læse",
+ "* tilføj artikler til din læseliste, * så du altid let kan finde dem igen, * ligegyldig om du er på computer eller mobil, * og læse lige når du har tid,",
+ "sådan følger du",
+ "følg et emne eller en skribent og vær sikker på, du får det hele med.",
+ "* klik på følg ud for et tag eller en skribent, * vi kan sende dig en email, når en ny artikel udgives, * alle artikler samles i et feed på siden du følger, som du finder i højre hjørne under dit navn og i sidepanelet, * hver mandag får du en email med de mest læste artikler om det, du følger.",
+ "du kan altid justere dine emails i indstillinger,",
+ "næste: næste:",
+ "bliv abonnent, og lyt med",
+ "læs artiklen senere gemt (klik for at fjerne) læst",
+ "giv artiklen videre",
+ "som abonnent kan du ubegrænset dele artikler med dine venner og familie.",
+ "læs mere om fordelene ved et abonnement her.",
+ "redaktionen anbefaler",
+ "* internationalt,",
+ "om politiken",
+ "organet for den højeste oplysning siden 1884",
+ "rådhuspladsen 37",
+ "kontakt redaktionen: 33 11 85 11",
+ "kontakt kundeservice: 70 15 01 01",
+ "politikens vision",
+ "politikens journalistik og etik",
+ "chefredaktionen",
+ "christian jensen (ansvarshavende)",
+ "amalie kestler",
+ "digital direktør",
+ "troels behrendt jørgensen",
+ "kommerciel direktør",
+ "astrid jørgensen",
+ "digital udviklingschef",
+ "marie bering",
+ "digital redaktionschef",
+ "thomas berndt",
+ "annoncedirektør",
+ "thomas hervø",
+ "forsideredaktør lige nu",
+ "ove kusnitzoff",
+ "politiken digital",
+ "politiken kombi lørdag",
+ "politiken komplet",
+ "kundecenter",
+ "copyright politiken 2023",
+ "tekst, grafik, billeder, lyd og andet",
+ "indhold på dette website er",
+ "beskyttet efter lov om ophavsret.",
+ "politiken forbeholder sig alle",
+ "rettigheder til indholdet, herunder",
+ "retten til at udnytte indholdet",
+ "med henblik på tekst- og",
+ "datamining, jf.",
+ "ophavsretslovens",
+ "§ 11 b og dsm-direktivets artikel 4",
+ "læs mere om ophavsret",
+ "artiklen er låst – sådan kommer du videre:",
+ "vil du have adgang?",
+ "vil du tillade dataindsamling?",
+ "som abonnent kan du tilpasse hvilken data, der indsamles.",
+ "du kan altid trække dit samtykke tilbage.",
+ "artiklen er føjet til din læseliste du har ulæste artikler på din læseliste",
+ "log ind køb abonnement",
+ "* e-avisen, * politiken live, * nyhedsbreve, * podcast, * politiken plus,",
+ "* sektionerdanmarkkulturdebatklimainternationaltsportforbrug og livibyense alle,",
+ "* podcastdu lytter til...madsen & magtenbogfolkkongerækkense alle,",
+ "* underholdningatsbezzerwizzersudokukrydsordse alle,",
+ "* andetmit politikenarkivbilletkontakt osadministrér samtykkerss feedsjobskøb abonnement,",
+ "klimamonitor byrummonitor skolemonitor sundhedsmonitor kulturmonitor idrætsmonitor turistmonitor",
+ "sommertilbud:spar 50% hver måned i 6 måneder",
+ "læs hele samlingen →",
+ "her er principperne bag ukraines store offensiv: »på papiret er der ingen tvivl om, at det er det rette sted at angribe«",
+ "forstærkningerne er ankommet til den russiske skyttegrav på den anden side af marken – og de sniger sig ud om natten",
+ "scenarierne er på bordet: her er fem mulige afslutninger på krigen i ukraine",
+ "de ligger bare der.",
+ "kolonner af togvogne fyldt med russiske lig: »der er hundredvis af lig.",
+ "jeg tror ikke engang, militæret har tal på dem«",
+ "»jeg beder dig forstå risikoen«, lød afslaget.",
+ "en anden bekendt fra rusland har slet ikke svaret.",
+ "tavsheden får det til at løbe koldt ned ad ryggen",
+ "»jeg troede, jeg skulle have en god og rolig alderdom.",
+ "men det her ... det ønsker jeg ikke for nogen«",
+ "»vi beder ikke om, at i kommer og redder os«: en af ukraines mest jagede mænd har en særlig besked til danmark",
+ "bomberne falder over ukraine og rammer civilbefolkningen.",
+ "historien tegner et grusomt billede",
+ "putin har flere gange truet med atomvåben.",
+ "hvor langt er vi fra det utænkelige, og hvordan kan det ske?",
+ "politiken i izjum: sådan ser der ud i helvede",
+ "max forklarer, hvad der sker, når infanteriet sætter sig i bevægelse: »det er sådan, man undgår svære tab«",
+ "en erfaren soldat ser, hvad 26-årige andriy har gang i. det giver et spjæt i soldaten, som springer hen til ambulancen",
+ "ukrainsk superwoman er rasende på zelenskyj: »efter min mening begår vores regering en stor fejl«",
+ "der er ikke noget, der kan forberede en på kharkivs metrostationer",
+ "de er 21 år, og deres hverdag er geopolitik, tiktok, tv-serier, stinger-missiler og at grine ad fyre, der sender latterlige beskeder",
+ "det, der gør størst indtryk på fotografen og mig er, at de alle virker så nervøse",
+ "»nu forstår det ukrainske folk, hvad rusland er«",
+ "en chokeret verden ser på billederne af det, der tyder på en russisk massakre",
+ "tak for din tilmelding!",
+ "vis alle nyhedsbreve her kan du læse mere om, hvordan vi håndterer dine personoplysninger.",
+ "luk beskedvindue",
+ "er kun for abonnenter!",
+ "med et digitalt abonement får du fuld adgang til hele politiken.dk, alle nyhedsbreve og e-avisen leveret hver aften.",
+ "første måned 1 kr.",
+ "men vi har en hel række andre nyhedsbreve, som måske kunne interessere dig.",
+ "se alle nyhedsbreve",
+ "vi beklager!",
+ "der skete en fejl, prøv igen senere",
+ "der skete en fejl, prøv igen senere eller søg hjælp via vores kundecenter",
+ "prøv 30 dage for kun 1 kr.",
+ "få adgang til vores digitale univers, og læs artikler, lyt til podcasts og løs krydsord.",
+ "essay: adhd plejede at være en drenge-diagnose, men nu myldrer det frem med voksne kvinder, der får diagnosen.",
+ "jeg er en af dem",
+ "* forbrug og liv,",
+ "de har besøgt 101 spisesteder og barer det seneste år.",
+ "her er alle anmeldernes højdepunkter",
+ "hun er fyldt 101 år.",
+ "og når hun kigger på københavn i dag, lægger hun især mærke til noget særligt ved mændene ved søerne",
+ "den lille lasede pige hiver efter vejret, da hun kommer op af hullet med glimmerstenene til din mobil, makeup og elbil",
+ "film og tv: guld fra arkivet",
+ "'kedelig film' er verdens bedste ifølge listen, som alle filmeksperter respekterer",
+ "* film og tv,",
+ "politiken podcast",
+ "agenterne - et liv mellem to verdener",
+ "alle har hørt om samsam-sagen – vi fortæller fire andre historier fra den hemmelige verden.",
+ "hvad driver agenterne, og hvorfor går det nogle gange helt galt?",
+ "politiken fortæller",
+ "søren ulrik thomsens øjesten er egentlig godkendt til nedrivning: »det illustrerer, hvor vigtigt dette arbejde er«",
+ "* hovedstaden,",
+ "inge lis troede, hun havde fundet sit livs kærlighed, men mistede 230.000 kroner.",
+ "og så endte det helt galt",
+ "nu fortæller matilde kimer sin side af historien: det stikker helt af for mig, da han lægger en ’løsningsmodel’ på bordet",
+ "nyt nyhedsbrev: det, i taler om",
+ "hver lørdag samler opinionschef lotte folke de bedste indlæg om alt det, i taler om.",
+ "du er nu tilmeldt nyhedsbrevet det, i taler om.",
+ "nyhedsbrevet nyt nyhedsbrev: det, i taler om er kun for abonnenter!",
+ "du er allerede tilmeldt nyhedsbrevet nyt nyhedsbrev: det, i taler om",
+ "dr's hovedindgange",
+ "dr.dkdrtvdr lyd",
+ "gå til forsiden",
+ "sektionens indgange",
+ "* seneste nyt, * indland, * udland, * penge, * politik, * regionalt, * vejret,",
+ "mere fra dr.dk",
+ "gå til forsiden af dr.dk",
+ "* politik, * meningsmåling, * folketingsvalg, * folkeafstemning, * kommunal- og regionalvalg,",
+ "gå til hovedindhold",
+ "* abonnement,",
+ "* nyheder, * blogs, * debat, * avisnyeste avis og arkivingeniørens danmarkshistoriekontakt, * fokusalle fokusprofilanalysen 2023klimamål 2030lynetteholm-projektetpfasslut med russisk gaspower-to-xmånerejsencrisprkrigens teknologinord stream-lækagenspacexspørg fagfolkettech weekly, * ida-adgang, * job, * meretip osnyhedsbreveeventpodcastemneoversigtvidensbanknavnenytapprss-feedabonnement,",
+ "* abonnementervi har to typer abonnementer - plus og pro, * nyhedsbrevefå det bedste fra ing/ på mail, * ing/jobfinderlige nu ca.",
+ "450 ledige job til ingeniører, tekniske specialister og it-professionelle, * eventsse og læs mere om alle vores kommende konferencer, briefings og messer, * vidensbankwhitepapers, webinarer og videnspakker, der giver dig fagligt perspektiv og inspiration til dit arbejdsliv.,",
+ "digitale medier",
+ "* ing/vi har kvalificeret din tech-viden siden 1892, * ing/version2den skarpeste dækning af de vigtigste it-nyheder, * ing/radarfordi tech er politisk, * ing/pronicheviden for professionelleing/buildingtechbyggeri, renovering og vedligeholding/caretechvelfærdsteknologi og hjælpemidlering/compliancetechgdpr og complianceing/datatechanalytics og dataing/digitechoffentlig digitalisering og it-projektering/gridtechenergi og elektrificeringing/mobilitytechtransport og trafiking/tech managementteknologi, forretning og ledelseing/wastetechaffald og genanvendelseing/watertechteknologi og vandets kredsløb, * transformatorugentlig podcast med teknologiske nyheder og tendenser,",
+ "printmedier",
+ "* ingeniørenhver anden fredag, * tech managementstyrk ledelsen af den teknologiske transformation - magasin 2 gange om året,",
+ "kommercielt",
+ "* tech relationsteknologiens b2b branding- og kommunikationsbureau, * ing/peopletechom rekruttering og fastholdelse af tekniske specialister., * teknologiens mediehusvi bygger bro med stærke vidensmedier, relevante events, nærværende netværk og ing/jobfinder hvor vi forbinder kandidater og virksomheder.,",
+ "har du feedback eller brug for teknisk hjælp kan du skrive til vores support.",
+ "bliv abonnent",
+ "chevron_left",
+ "chevron_right",
+ "plus-abonnement",
+ "dit medlemskab giver adgang",
+ "som medlem af ida har du gratis adgang til plus-indhold, som en del af dit medlemskab.",
+ "fortsæt med mitida for at aktivere din adgang til indholdet.",
+ "fortsæt med mitida",
+ "oplever du problemer med login, så skriv til os på websupport@ing.dk",
+ "abonnementsfordele",
+ "fuld adgang til ing.dk, version2 og radar",
+ "fuld digital adgang til plus-indhold på ing.dk, version2 og radar, tilgængeligt på din computer, tablet og mobil.",
+ "kuraterede nyhedsbreve",
+ "det seneste nye fra branchen, leveret til din indbakke.",
+ "adgang til debatten",
+ "deltag i debatten med andre kloge læsere.",
+ "ingen kommentarer endnu.",
+ "start debatten",
+ "* facebook, * twitter, * linkedin, * emaile-mail, * linkkopier link,",
+ "ing/jobfinderchevron_right",
+ "opret jobannonce",
+ "er det dig?",
+ "log ind eller opret en bruger for at deltage i debatten.",
+ "settingsdebatvisning",
+ "* sortér efter chevron_rightthumb_upbedstewb_sunnynyestehistoryældste, * trådet debat,",
+ "om teknologiens mediehus",
+ "vi bygger bro med stærke vidensmedier, relevante events, nærværende netværk og teknologiens jobfinder, hvor vi forbinder kandidater og virksomheder.",
+ "mere om teknologiens mediehus",
+ "abonnement & nyhedsbreve",
+ "læs her om vores forskellige abonnementstyper",
+ "med vores nyhedsbreve får du et fagligt overblik og adgang til levende debat mellem fagfolk.",
+ "annoncering",
+ "teknologiens mediehus tilbyder en bred vifte af muligheder for annoncering over for ingeniører og it-professionelle.",
+ "hvad kan vi tilbyde?",
+ "tech relations leverer effektiv formidling af dit budskab til ingeniører og it-professionelle.",
+ "ing/jobfinder",
+ "danmarks største jobplatform for ingeniører, it-professionelle og tekniske specialister.",
+ "* find job, * indryk job, * kontakt salg,",
+ "kalvebod brygge 33, 1560 københavn v",
+ "adm. direktør christina blaagaard collignon",
+ "chefredaktør trine reitz bjerregaard",
+ "kontakt redaktionen",
+ "* om, * kontakt, * vores politikker, * priser og abonnementsbetingelser, * annoncer hos os, * cookiedeklaration,",
+ "© 1994 - 2023 teknologiens mediehus",
+ "* more_vertinsert_linkkopier link,",
+ "»om aftenen er det, som om det går op for mig, at irma lukker.",
+ "jeg sover normalt virkelig godt, men jeg kan ikke sove, jeg ligger bare«",
+ "det meste er opfanget af bakkegårdens overvågningskameraer: vikarerne hilser på de indsatte som venner.",
+ "og så stikker det helt af",
+ "niels holst",
+ "det er ikke første verdenskrig – men det ligner",
+ "jeppe dong abrahamsen",
+ "* den levendehenter...49:47manden: »vi står midt i en manderevolution«, * poptillæggethenter...56:28ingen kan forene hjertesorg, queervrede og klimakrise, som anohni gør, * du lytter til politikenhenter...30:4611. august: hiphop fylder 50 år – hvad fuck fejrer vi?, * du lytter til politikenhenter...27:2510. august: kan biden hjælpe de sorte uden at snyde de hvide?,",
+ "eva holtegaard-kasler",
+ "* meme dig til magtenhenter...33:35meme dig til magten: farvel syg arbejdskultur, hello #lazygirljobbliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "login, * poptillæggethenter...63:55ingen ved, om de skal elske eller hade 'and just like that', * du lytter til politikenhenter...28:3018. august: digital dopamin: derfor kan du ikke styre dit skærmforbrug, * den levendehenter...49:26magt: »magt er overalt og næsten umulig at få greb om«bliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "* sport, * vm atletik, * live, * resultater, * features,",
+ "om måneden.",
+ "sidste chance: spar 50% hver måned i 6 måneder",
+ "* du lytter til politikenhenter...23:4325. august: trump: elefanten, der ikke er i rummet, * valgethenter...16:06er der nogen, der ved, hvor de har ellemann?bliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "login, * den levendehenter...44:30vrede kvinder: »jeg ser vreden som nogle naturlige grænser, vi har«, * du lytter til politikenhenter...32:5924. august: rumrejsen: andreas og de sære ritualer,",
+ "den anden stak af.",
+ "login, * bogfolkhenter...42:45karoline stjernfelt: »det har både været enormt gavnligt og enormt skadeligt med den opmærksomhed, kroppen har fået gennem sociale medier«bliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "login, * du lytter til politikenhenter...23:231. september: hvorfor har vi ikke fri hash i danmark?, * valgethenter...16:40nu gør vanopslagh sig lækker for en jysk tømrermesterbliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "* meme dig til magtenhenter...32:18meme dig til magten: derfor har en klapstol oversvømmet internettetbliv abonnent, og lyt meddu skal være abonnent for at lytte til denne automatiske oplæsning.køb abonnementallerede abonnent?",
+ "få adgang til artikler på jp.dk",
+ "prøv 3 måneder for 99 kr.",
+ "få adgang nu",
+ "v/betaling med kreditkort el.",
+ "fortsætter automatisk som løbende abonnement til 99 kr.",
+ "fortrydelsesret i medfør af forbrugeraftaleloven.",
+ "*fast intropris for 3 mdr.",
+ "til nye kunder, der ikke har været kunder hos jyllands-posten de seneste seks mdr.",
+ "måned efter de første 3 mdr.",
+ "kan opsiges med 1 dags varsel til udløb af introduktionsperioden.",
+ "mindstepris for 3 mdr.",
+ "læs artiklen senere\n gemt (klik for at fjerne)\n læst",
+ "fortsætter herefter til 99 kr.",
+ "fortrydelsesret jf.",
+ "forbrugeraftaleloven.",
+ "\læs også",
+ ]
+ + [ # German Patterns
+ "folgen ich folge",
+ "mehr zum thema 1/",
+ "der überblick.",
+ "bild: reuters",
+ "ein gastbeitrag.",
+ "bild: picture alliance",
+ "sie können den artikel leider nicht mehr aufrufen.",
+ "der link, der ihnen geschickt wurde, ist entweder älter als 30 tage oder der artikel wurde bereits 10 mal geöffnet.",
+ "digital-abo",
+ "sagen, was ist.",
+ "testen sie das digitale angebot und erfahren sie, warum mehr als 400.000 menschen den spiegel abonnieren.",
+ "kennenlernangebot - 4 wochen für € 1,–",
+ "jetzt abonnieren",
+ "ihre bezahlmöglichkeiten:",
+ "jederzeit kündigen.",
+ "mehr perspektiven, mehr verstehen.",
+ "freier zugang zu allen artikeln, videos, audioinhalten und podcasts",
+ "alle artikel auf spiegel.de frei zugänglich",
+ "der spiegel als e-paper und in der app",
+ "alle artikel zum anhören und exklusive podcasts",
+ "nur € 21,99 pro monat, jederzeit kündbar",
+ "sie haben bereits ein digital-abonnement?",
+ "spiegel+ wird über ihren itunes-account abgewickelt und mit kaufbestätigung bezahlt.",
+ "in den einstellungen ihres itunes-accounts können sie das abo jederzeit kündigen.",
+ "um spiegel+ außerhalb\ndieser app zu nutzen, müssen sie das abo direkt nach dem kauf mit einem spiegel-id-konto verknüpfen.",
+ "mit dem kauf akzeptieren sie unsere\nallgemeinen geschäftsbedingungen und datenschutzerklärung.",
+ "zum inhalt springen",
+ "der spiegel wirtschaft",
+ "abonnement abo anmelden",
+ "* e-mail, * messenger, * whatsapp,",
+ "spiegel plus anmelden",
+ "ihre bezahlmöglichkeiten: paypal sepa visa mastercard applepay googlepay",
+ "weiterlesen mit spiegel+",
+ "* alle artikel auf spiegel.de frei zugänglich, * der spiegel als e-paper und in der app, * alle artikel zum anhören und exklusive podcasts, * nur € 21,99 pro monat, jederzeit kündbar, * nur € 19,99 pro monat, jederzeit kündbar,",
+ "24 stunden vor ablauf verlängert sich das abo automatisch um einen monat zum preis von zurzeit 19,99€.",
+ "um spiegel+ außerhalb dieser app zu nutzen, müssen sie das abo direkt nach dem kauf mit einem spiegel-id-konto verknüpfen.",
+ "mit dem kauf akzeptieren sie unsere allgemeinen geschäftsbedingungen und datenschutzerklärung.",
+ "kostenlose online-spiele",
+ "mehr spiele",
+ "* kreuzworträtsel, * solitär, * sudoku, * mahjong, * bubble-shooter, * jackpot, * snake, * exchange, * 2048, * doppel, * rushtower, * sudoken, * street, * wortblitz, * fibonacci, * gumblast, * wimmelbild, * skiracer, * trivial pursuit,",
+ "serviceangebote von spiegel-partnern",
+ "ebay gutscheine",
+ "christ gutscheine",
+ "expedia gutscheine",
+ "tink gutscheine",
+ "top gutscheine alle shops",
+ "* bußgeldrechner, * firmenwagenrechner,",
+ "* brutto-netto-rechner, * jobsuche, * kurzarbeitergeld-rechner, * studienfächer erklärt,",
+ "* gehaltsvergleich, * immobilienbewertung, * studium und finanzen, * versicherungen, * währungsrechner,",
+ "* bücher bestellen, * eurojackpot, * ferientermine,",
+ "* glücksspirale, * gutscheine, * lotto 6aus49,",
+ "* seniorenportal, * spiele, * das tägliche quiz,",
+ "alle magazine des spiegel",
+ "* der spiegel, * spiegel geschichte, * spiegel wissen, * spiegel start, * spiegel geld, * spiegel coaching, * spiegel chronik, * spiegel spezial, * dein spiegel, * spiegel edition, * spiegel bestseller, * s-magazin, * spiegel leben, * spiegel biografie,",
+ "spiegel gruppe",
+ "abo abo kündigen shop manager magazin harvard business manager buchreport werbung jobs manufaktur spiegel akademie spiegel ed",
+ "impressum datenschutz nutzungsbedingungen teilnahmebedingungen cookies & tracking newsletter kontakt hilfe text- & nutzungsrechte",
+ "facebook twitter wo sie uns noch folgen können",
+ "die wiedergabe wurde unterbrochen.",
+ "teilen sie ihre meinung mit",
+ "melden sie sich an und diskutieren sie mit",
+ "speichern sie ihre lieblingsartikel in der persönlichen merkliste, um sie später zu lesen und einfach wiederzufinden.",
+ "anmelden oder konto erstellen",
+ "mehrfachnutzung erkannt",
+ "bitte beachten sie: die zeitgleiche nutzung von spiegel+-inhalten ist auf ein gerät beschränkt.",
+ "wir behalten uns vor, die mehrfachnutzung zukünftig technisch zu unterbinden.",
+ "sie möchten spiegel+ auf mehreren geräten zeitgleich nutzen?",
+ "zu unseren angeboten",
+ "der spiegel politik",
+ "mehr lesen über",
+ "verwandte artikel",
+ "mister spex gutscheine",
+ "lampenwelt gutscheine",
+ "conrad gutscheine",
+ "belvini gutscheine",
+ "speichern sie audioinhalte in ihrer playlist, um sie später zu hören oder offline abzuspielen.",
+ "zusätzlich können sie ihre playlist über alle geräte mit der spiegel-app synchronisieren, auf denen sie mit ihrem konto angemeldet sind.",
+ "der spiegel panorama",
+ "h&m gutscheine",
+ "thalia gutscheine",
+ "foot locker gutscheine",
+ "sephora gutscheine",
+ "mehr zum thema",
+ "empfohlener externer inhalt",
+ "an dieser stelle finden sie einen externen inhalt von twitter, der den artikel ergänzt und von der redaktion empfohlen wird.",
+ "sie können ihn sich mit einem klick anzeigen lassen und wieder ausblenden.",
+ "externer inhalt",
+ "ich bin damit einverstanden, dass mir externe inhalte angezeigt werden.",
+ "damit können personenbezogene daten an drittplattformen übermittelt werden.",
+ "mehr dazu in unserer datenschutzerklärung.",
+ "zur datenschutzerklärung",
+ "artikel zum hören•2 min",
+ "der spiegel ausland",
+ "booking gutscheine",
+ "eis.de gutscheine",
+ "hellofresh gutscheine",
+ "otto gutscheine",
+ "der spiegel sport",
+ "adidas gutscheine",
+ "asos gutscheine",
+ "nike gutscheine",
+ "lidl gutscheine",
+ "startseite home : 0 neue oder aktualisierte artikel.",
+ "* inland, * ausland, * politische bücher, * geschichte, * briefe an die herausgeber,",
+ "* historische hyperinflation, * digitec, * unternehmen, * wohnen, * auto & verkehr, * klima & nachhaltigkeit, * arm und reich, * schneller schlau, * wirtschaftswissen,",
+ "* accenture: wandel gestalten,",
+ "* meine finanzen, * finanzmarkt, * börsen & märkte,",
+ "* mein depot, * börsenlexikon, * börsenspiel, * die digitale zukunft finanzieren,",
+ "* debatten, * bücher, * medien, * kino, * pop, * bühne und konzert, * kunst und architektur, * kunstmarkt, * familie, * tv- & radioprogramm,",
+ "karriere & hochschule",
+ "* büro & co, * hörsaal, * klassenzimmer, * die karrierefrage,",
+ "* fußball, * frauenfußball-wm, * formel 1, * mehr sport, * rhein-main-sport, * sportpolitik, * sport-tipps, * sport live, * sport-ergebnisse,",
+ "gesellschaft",
+ "* menschen, * kriminalität, * unglücke, * gesundheit, * tiere, * smalltalk, * jugend schreibt,",
+ "* bierkultur, * mit tempo in die digitale zukunft,",
+ "* mode & design, * essen & trinken, * leib & seele, * trends & nischen, * quarterly,",
+ "* frankfurt, * region und hessen, * wirtschaft, * kultur, * sport, * f.a.z.",
+ "leser helfen,",
+ "* veranstaltungen,",
+ "technik & motor",
+ "* motor, * elektromobilität, * technik, * digital, * energie,",
+ "* medizin & ernährung, * krebsmedizin, * weltraum, * leben & gene, * erde & klima, * physik & mehr, * archäologie & altertum, * geist & soziales, * forschung & politik, * ab in die botanik, * netzrätsel,",
+ "* wetter, * winterthur, * f.a.z.",
+ "leserreisen,",
+ "agenturmeldungen",
+ "datenschutz",
+ "nutzungsbedingungen",
+ "aktuelle nachrichten aus politik, wirtschaft, sport und kultur",
+ "herausgegeben von gerald braunberger, jürgen kaube, carsten knop, berthold kohler",
+ "zeitung faz.net",
+ "bildbeschreibung einblenden",
+ "quelle: f.a.z.",
+ "hier können sie die rechte an diesem artikel erwerben.",
+ "zur startseite",
+ "weitere themen",
+ "ähnliche themen",
+ "topmeldungen",
+ "immer auf dem laufenden sie haben post!",
+ "die wichtigsten nachrichten direkt in ihre mailbox.",
+ "sie können bis zu 5 newsletter gleichzeitig auswählen es ist ein fehler aufgetreten.",
+ "bitte versuchen sie es erneut.",
+ "vielen dank für ihr interesse an den f.a.z.-newslettern.",
+ "sie erhalten in wenigen minuten eine e-mail, um ihre newsletterbestellung zu bestätigen.",
+ "administrative managing director (m|f|d)",
+ "gsi helmholtzzentrum für schwerionenforschung gmbh",
+ "administrative*r geschäftsführer*in (m|w|d)",
+ "über dr. maier + partner gmbh executive search",
+ "zum stellenmarkt",
+ "verlagsangebot",
+ "* douglas-rabattcode,",
+ "* parfumdreams-gutschein,",
+ "* flaconi-gutschein,",
+ "* parfümerie pieper-rabattcode,",
+ "* sephora-rabattcode,",
+ "* notino-rabattcode,",
+ "* mac-gutschein,",
+ "* niche beauty-rabattcode,",
+ "* e-bike-test,",
+ "* powerbank-test,",
+ "* inhalator-test,",
+ "* fensterputzroboter,",
+ "* abo-service, * best ager, * selection shop, * firmen, * finanz-services, * tarifrechner, * newsletter, * immobilien- markt, * testberichte, * stellenmarkt, * spiele, * gutscheine, * veranstaltungen, * sport-ergebnisse, * tv-programm, * wetter,",
+ "frankfurter allgemeine zeitung",
+ "* datenschutz, * cookie-manager, * einwilligung widerrufen, * werbefrei lesen, * nutzungsbedingungen,",
+ "* kontakt, * abo-angebote, * mediadaten,",
+ "* redaktion, * vertrauen, * über die f.a.z.,",
+ "* stellenmarkt, * tarifrechner, * immobilienmarkt,",
+ "* presse, * themen wirtschaft, * blogs, * impressum,",
+ "© frankfurter allgemeine zeitung gmbh 2001 - 2023 alle rechte vorbehalten.",
+ "beitrag per e-mail versenden",
+ "ein fehler ist aufgetreten.",
+ "bitte überprüfen sie ihre eingaben.",
+ "vielen dank der beitrag wurde erfolgreich versandt.",
+ "zugang zu allen f+ artikeln 2,95 € / woche jetzt 30 tage kostenfrei testen 2,95 € / woche jetzt kostenfrei zugang abonnieren?",
+ "mit einem klick online kündbar",
+ "weiter ja, 30 tage kostenfrei testen",
+ "diese und viele weitere artikel lesen sie mit f+",
+ "* maybrit illner, * tatort, * ferdinand von schirach,",
+ "* julian assange, * anne will, * new york times, * banksy,",
+ "* peter handke, * hart aber fair, * gez, * jan böhmermann,",
+ "* michel houellebecq, * bushido, * richard david precht, * claas relotius,",
+ "* haruki murakami, * astrid lindgren, * lady gaga, * attila hildmann,",
+ "* the north face-gutschein,",
+ "* radonline-gutschein,",
+ "* rose bikes-gutschein,",
+ "* groupon-gutschein,",
+ "* decathlon-gutschein,",
+ "* jack wolfskin-gutschein,",
+ "* mydays-gutschein,",
+ "* bike24-gutschein,",
+ "* kinderwagen-test,",
+ "* av-receiver-test,",
+ "* luftbefeuchter-test,",
+ "* trinkflaschen-test,",
+ "* presse, * themen feuilleton, * blogs, * impressum,",
+ "* küchenwaage-test,",
+ "* wassersprudler-test,",
+ "* windeleimer-test,",
+ "* toaster-test,",
+ "* presse, * themen gesellschaft, * blogs, * impressum,",
+ "lesermeinungen",
+ "* saturn-gutschein,",
+ "* amazon-gutschein,",
+ "* gopro-aktionscode,",
+ "* hp store-gutschein,",
+ "* grover-gutschein,",
+ "* samsung-gutscheincode,",
+ "* ebay-gutschein,",
+ "* kitchenaid-gutschein,",
+ "* wlan-repeater-test,",
+ "* laserdrucker-test,",
+ "* internetradio-test,",
+ "* espressomaschine-test,",
+ "* presse, * politik themen, * blogs, * impressum,",
+ "* westwing-gutschein,",
+ "* wayfair-rabattcode,",
+ "* massivmoebel24-gutschein,",
+ "* maisons du monde-gutschein,",
+ "* otto-gutschein,",
+ "* poco-gutschein,",
+ "* lampenwelt-gutschein,",
+ "* tchibo-gutschein,",
+ "* vaay-rabattcode,",
+ "* sanicare-gutschein,",
+ "* docmorris-gutschein,",
+ "* foodspring-gutschein,",
+ "* myprotein-gutschein,",
+ "* shop apotheke-gutschein,",
+ "* lensbest-gutschein,",
+ "* medpex-gutschein,",
+ "* wanderstöcke-test,",
+ "* fahrrad-navi-test,",
+ "* damen-wanderschuhe,",
+ "* fitnessband-test,",
+ "* presse, * sport themen, * blogs, * impressum,",
+ "permalink: https://www.faz.net/-gpf-bbvzq",
+ "janina käppel",
+ "twitter.com",
+ "link kopieren",
+ "share on facebook",
+ "share on twitter",
+ "share via email",
+ "philipp johannßen",
+ "martin franke",
+ "tickaroolive blog software",
+ "* veröffentlicht/aktualisiert:,",
+ "quelle: faz.net",
+ "artikel zum hören•3 min",
+ "cyberport gutscheine",
+ "personalleitung (m/w/d)",
+ "quelle: dpa",
+ "artikel auf einer seite lesen",
+ "anna-lena ripperger",
+ "mitarbeiter (m/w/d) studienberatung & sales frankfurt am main",
+ "fom hochschule für oekonomie & management gemeinnützige gesellschaft mbh",
+ "vanessa angermann",
+ "* twitter, * facebook, * e-mail, * messenger, * whatsapp,",
+ "zur ausgabe",
+ "anna schiller",
+ "jannik müller",
+ "über fricke finance & legal",
+ "nicolas kurzawa",
+ "othmara glas",
+ "katharina moser",
+ "henrik bahlmann",
+ "* mit tempo in die digitale zukunft,",
+ "* wetter, * bis tief in polare gebiete, * winterthur, * f.a.z.",
+ "klaus bardenhagen",
+ "simon hüsgen",
+ "sven scharf",
+ "gregor grosse",
+ "* fußball, * frauenfußball-wm, * formel 1, * mehr sport, * leichtathletik-wm, * rhein-main-sport, * sportpolitik, * sport-tipps, * sport live, * sport-ergebnisse,",
+ "simon röhricht",
+ "stefanie sommer",
+ "* fußball, * frauenfußball-wm, * formel 1, * mehr sport, * leichtathletik-wm, * us open, * rhein-main-sport, * sportpolitik, * sport-tipps, * sport live, * sport-ergebnisse,",
+ "* alle artikel auf spiegel.de frei zugänglich, * der spiegel als e-paper und in der app, * alle artikel zum anhören und exklusive podcasts, * nur € 21,99 pro monat, jederzeit kündbar,",
+ "24 stunden vor ablauf verlängert sich das abo automatisch um einen monat zum preis von zurzeit € 21,99.",
+ "fabian drahmoune",
+ "mathias peer",
+ "* debatten, * bücher, * unsere reisebegleiter, * medien, * kino, * pop, * bühne und konzert, * kunst und architektur, * kunstmarkt, * familie, * tv- & radioprogramm,",
+ "* inspiration für den lebensraum küche,",
+ "* der spiegel, * spiegel geschichte, * spiegel wissen, * spiegel start, * spiegel geld, * spiegel coaching, * spiegel chronik, * dein spiegel, * spiegel bestseller, * s-magazin, * spiegel edition, * spiegel spezial, * spiegel biografie,",
+ "* der spiegel, * spiegel spezial, * spiegel geschichte, * spiegel wissen, * spiegel start, * spiegel geld, * spiegel coaching, * dein spiegel, * spiegel bestseller, * s-magazin, * spiegel edition, * spiegel biografie, * spiegel chronik,",
+ "€ 2,99 pro woche für 52 wochen",
+ "€ 100,- sparen",
+ "24 stunden vor ablauf verlängert sich das abo automatisch um\neinen monat zum preis von zurzeit € 21,99.",
+ "optensteinen, charlene",
+ "sie können ihre zustimmung jederzeit wieder zurücknehmen.",
+ "irem yildirim",
+ "oliver kühn",
+ "philipp von reinersdorff",
+ "zugang zu allen faz+ beiträgen\n 11,80\xa0€\n jetzt nur 0,99\xa0€",
+ "jetzt zugang 11,80\xa0€ für nur 0,99\xa0€ abonnieren?",
+ "externer inhalt von youtube",
+ "um externe inhalte anzuzeigen, ist ihre widerrufliche zustimmung nötig.",
+ "dabei können personenbezogene daten von drittplattformen (ggf.",
+ "usa) verarbeitet werden.",
+ "weitere informationen .",
+ "zum jubiläum: 7 monate für nur 5 € pro monat testen",
+ "zum jubiläum: 7 monate für nur 5 € pro monat testen",
+ "malte müller-michaelis",
+ ]
+ + [ # French Patterns
+ "inscrivez-vous à notre newsletter.",
+ "musique et habillage : emmanuel herschon/studio torrent",
+ "logo : anne-laure chapelain/benjamin chazal",
+ "comment écouter un podcast ?",
+ "suivez le guide.",
+ "pour aller plus loin",
+ "retrouvez tous les episodes de la loupe",
+ "vous avez refusé les cookies associés aux contenus issus de tiers en vous abonnant.",
+ "vous ne pourrez donc pas lire nos vidéos qui ont besoin de cookies tiers pour fonctionner.",
+ "vous utilisez un bloqueur de publicité.",
+ "nous vous conseillons de le désactiver afin d’accéder à nos vidéos.",
+ "si vous n'êtes dans aucun de ces deux cas, contactez-nous à aide@huffingtonpost.fr vous ne pouvez pas visionner ce contenu car :",
+ "à voir également sur le huffpost :",
+ "photo presse",
+ "nos réponses.",
+ "la rédaction du figaro n‘a pas participé à la réalisation de cet article.",
+ "la rédaction du figaro n'a pas participé à la réalisation de cet article.",
+ "certains liens sont trackés et peuvent générer une commission pour le figaro.",
+ "contenu conçu et proposé par",
+ "contenu conçu et proposé par le figaro services.",
+ "les prix mentionnés dans cet article le sont à titre indicatif et sont susceptibles d’évoluer.",
+ "les prix mentionnés dans cet article le sont à titre indicatif.",
+ "lorsque vous achetez via nos liens de vente, nous pouvons percevoir une commission d’affiliation.",
+ "bertrand guay / afp",
+ "alain jocard / afp",
+ "geoffroy van der hasselt / afp",
+ "thomas samson / afp",
+ "aller au contenu",
+ "lire le journal",
+ "vente flash -70% pendant 1 an",
+ "* lien copié, * mail, * facebook, * twitter, * linkedin, * messenger, * whatsapp,",
+ "la rédaction vous conseille",
+ "aucun commentaire",
+ "il n'y a actuellement aucun commentaire concernant cet article.",
+ "soyez le premier à donner votre avis !",
+ "à lire aussi",
+ "plus de services",
+ "l'actualité à ne pas manquer",
+ "* résultats des élections, * covid-19, * guerre en ukraine, * tension iran-etats unis, * corée-du-nord, * actualité politique en temps réel, * analyses, débats politiques et sociétaux, * actualité et réseaux sociaux,",
+ "programme tv",
+ "* programme tv ce soir, * programme tv en ce moment, * programme tv tnt, * séries netflix, hbo, ocs et tv, * election et photos miss france, * programme tv canalsat, * programme tv free, * programme tv sfr, * actu people,",
+ "* calendriers et résultats des matchs en direct, * coupe du monde de rugby 2023, * jeux olympiques, * actualité cyclisme, * résultats, classement général tour de france, * qualifications euro 2024, * classement ligue 1, * classement top 14, * transferts football, * coupe du monde 2022, * ballon d'or france football,",
+ "* horoscope du jour, * guide du mariage, * recettes de cuisine, * brigitte macron, * actu mode, * apéritif dînatoire, * recette pâte à crêpe, * tendance bijoux, * meghan markle, * gainer son corps,",
+ "* fiches et guides des médicaments, * astuces et conseils bien-être, * santé et sexualité, * index des maladies, * conseils alimentation, nutrition et santé, * l'encyclopédie des organes, * conseils en psychologie, * la pollution va t-elle nous tuer ?, * apnée du sommeil : comment mieux dormir ?, * 15 mythes sur les vertus des aliments,",
+ "guide d'achat",
+ "* guide d'achat maison et jardin, * guide d'achat santé et beauté, * guide d’achat high-tech, * guide d'achat smartphones et tablettes, * comment choisir le meilleur extracteur de jus ?, * quelle est la meilleure montre connectée ?, * quel est le meilleur home cinéma sans fil ?, * comparatif semelle gel, * quel épilateur électrique choisir ?, * bons plans,",
+ "éducation et orientation",
+ "* résultats bac, * révisions du bac, * parcoursup, * annuaire des écoles de commerce, * les entreprises qui recrutent, * trouver un stage, * résultats brevet des collèges, * classement des écoles de commerce, * trouver une alternance, * agenda étudiant : jpo, salons...,",
+ "* succession de johnny hallyday, * sorties cinéma, * guide arts et expositions, * actualité musicale, * actualité jeux-vidéo, * citations et proverbes, * réservation de spectacles et théâtre, * sortir à paris, * histoire de france, * langue française,",
+ "codes promos et réductions",
+ "* code promo wish, * code promo cdiscount, * code promo shein, * code promo ebay, * code promo aliexpess, * code promo deliveroo, * code promo nike, * code promo sephora, * code promo showroomprive, * code promo asos,",
+ "offres d'emploi",
+ "* toutes les offres d'emploi, * emploi à paris, * emploi à lyon, * emploi à toulouse, * emploi à nantes, * emploi à bordeaux, * emploi commercial, * emploi contrôleur de gestion, * emploi logistique, * emploi communication, * nos fiches métiers,",
+ "annonces immobilières",
+ "* annonces immobilières, * achat appartement paris, * achat appartement nice, * achat appartement cannes, * achat appartement bordeaux, * achat appartement lyon, * achat appartement aix-en-provence, * achat maison bordeaux, * achat maison marseille, * achat maison montpellier,",
+ "économie argent et finances",
+ "* simulateur de seuil de richesse, * actualité économique et analyses, * impôts sur le revenu : simulateur, * palmarès des villes où investir dans l'immobilier, * studios et 2-pièces : les loyers ville par ville, * calculer l'impôt à payer, * barême des droits de succession et donation, * indice de référence des loyers (irl), * en france, les hauts revenus sont-ils tous des «riches»?, * carte familles nombreuses : jusqu’à 75 % de réduction sur les billets de train,",
+ "* guide des croisières, * guide voyage jordanie, * guide voyage namibie, * guide voyage maroc, * guide voyage new york, * guide voyage birmanie, * guide voyage lille, * guide voyage antilles, * guide voyage japon, * guide voyage amsterdam,",
+ "les magazines figaro",
+ "* le figaro magazine, * madame figaro, * le figaro, * le figaro hors-série, * le figaro histoire, * tv magazine, * f, l'art de vivre,",
+ "figaro services",
+ "* scpi de rendement, * changer d’assurance de prêt immobilier, * le village de l'emploi avis, * alarme maison, * demande de carte grise en ligne, * définition du portage salarial, * stress et troubles du sommeil, * a savoir en france, * annonces légales,",
+ "* primeurs, * comprendre le vin, * tops et sélections, * domaines et vignerons, * economie du vin, * foire aux vins, * magazine du vin, * spititueux, * cocktails et mixologie, * terroir et viticulture,",
+ "résultats des élections par département",
+ "* résultats des élections hauts-de-seine, * résultats des élections seine-saint-denis, * résultats des élections val-de-marne, * résultats des élections val-d'oise, * résultats des élections yvelines, * résultats des élections var, * résultats des élections alpes-maritimes, * résultats des élections essonne, * résultats des élections nord,",
+ "résultats des élections par région",
+ "* résultats des élections auvergne-rhône-alpes, * résultats des élections bourgogne-franche-comté, * résultats des élections bretagne, * résultats des élections centre-val de loire, * résultats des élections corse, * résultats des élections grand est, * résultats des élections hauts-de-france, * résultats des élections ile-de-france, * résultats des élections normandie, * résultats des élections nouvelle-aquitaine, * résultats des élections occitanie, * résultats des élections pays de la loire, * résultats des élections provence-alpes-côte d'azur,",
+ "résultats des élections par ville",
+ "* résultats des élections paris, * résultats des élections marseille, * résultats des élections lyon, * résultats des élections toulouse, * résultats des élections nice, * résultats des élections nantes, * résultats des élections montpellier, * résultats des élections strasbourg, * résultats des élections bordeaux, * résultats des élections lille, * résultats des élections rennes, * résultats des élections reims, * résultats des élections saint-étienne,",
+ "le figaro : editions locales",
+ "* le figaro bordeaux, * le figaro lyon, * le figaro nantes, * le figaro nice,",
+ "suivez l’actu en temps réelavec l’application le figaro",
+ "vous avez choisi de refuser les cookies",
+ "et pourtant, la publicité personnalisée est un moyen de soutenir le travail de notre rédaction qui s’engage à vous proposer chaque jour une information de qualité.",
+ "en acceptant les cookies, vous pourrez accéder aux contenus et fonctionnalités gratuites que propose notre site.",
+ "à tout moment, vous pouvez modifier vos choix via le bouton “paramétrer les cookies” en bas de page.",
+ "ourefuser et s'abonner",
+ "partager via :",
+ "* mail, * facebook, * twitter, * whatsapp, * lien copié, * messenger,",
+ "plus d'options",
+ "nos liens utiles",
+ "* nos applications mobiles, * les vidéos figaro live, * les podcasts du figaro, * les programmes tv, * les résultats sportifs, * carnet du jour, * figaro store, * le figaro bordeaux, * le figaro lyon, * le figaro nantes, * le figaro nice,",
+ "lire ce numéro",
+ "* découvrez toutes les offresles articles en illimité à partir de 0,99€ sans engagement, * gérer votre abonnement, * espace personnel,",
+ "applications mobiles",
+ "* le figaro : iphone | android, * le figaro jeux : iphone | android, * le kiosque le figaro : iphone | android, * le figaro cuisine : iphone | android,",
+ "nos newsletters",
+ "inscrivez-vous aux newsletters",
+ "suivez-nous sur :",
+ "* plan du site, * confidentialité, * cgu, * cgv, * info cookies, * charte, * aide et contact, * mentions légales, * abonnements, * newsletter, * publicité, * sitemap,",
+ "regarder la vidéo",
+ "à découvrir",
+ "consulter le journal",
+ "le monde - retour à la une",
+ "se connecter se connecter s’abonner dès 5,49 €/mois",
+ "temps de lecture 2 min.",
+ "* ajouter à vos sélectionsajouter à vos sélectionspour ajouter l’article à vos sélections identifiez-vouss’inscrire gratuitementvous possédez déjà un compte ?",
+ "se connecter, * partagerpartager sur facebookenvoyer par e-mailpartager sur whatsapppartager sur linkedin,",
+ "l’espace des contributions est réservé aux abonnés.",
+ "abonnez-vous pour accéder à cet espace d’échange et contribuer à la discussion.",
+ "édition du jour",
+ "lire le journal numérique",
+ "culture générale",
+ "des leçons interactives par la rédaction pour tester vos connaissances.",
+ "mots croisés",
+ "découvrez chaque jour une nouvelle grille de mots croisés.",
+ "le monde ateliers",
+ "cours du soir",
+ "cours en ligne, cours du soir, ateliers : développez vos compétences",
+ "lecture du monde en cours sur un autre appareil.",
+ "vous pouvez lire le monde sur un seul appareil à la fois",
+ "ce message s’affichera sur l’autre appareil.",
+ "découvrir les offres multicomptes",
+ "* parce qu’une autre personne (ou vous) est en train de lire le monde avec ce compte sur un autre appareil.vous ne pouvez lire le monde que sur un seul appareil à la fois (ordinateur, téléphone ou tablette)., * comment ne plus voir ce message ?en cliquant sur « » et en vous assurant que vous êtes la seule personne à consulter le monde avec ce compte., * que se passera-t-il si vous continuez à lire ici ?ce message s’affichera sur l’autre appareil.",
+ "ce dernier restera connecté avec ce compte., * y a-t-il d’autres limites ?non.",
+ "vous pouvez vous connecter avec votre compte sur autant d’appareils que vous le souhaitez, mais en les utilisant à des moments différents., * vous ignorez qui est l’autre personne ?nous vous conseillons de modifier votre mot de passe.,",
+ "lecture restreinte",
+ "votre abonnement n’autorise pas la lecture de cet article",
+ "pour plus d’informations, merci de contacter notre service commercial.",
+ "* les ateliers du monde, * mémorable : travailler sa mémoire, * mots croisés / sudokus, * résultats élections, * education, * gastronomie,",
+ "* les meilleures imprimantes laser, * les meilleurs aspirateurs robots, * jeux de société pour adultes,",
+ "* codes promo, * black friday, * soldes,",
+ "* le monde in english, * algérie, * belgique, * canada, * côte d’ivoire, * mali, * maroc, * sénégal, * suisse, * tunisie,",
+ "* découvrir le jardinage, * hits du moment, * formation professionnelle,",
+ "* le monde evènements, * courrier international, * télérama, * la vie, * le huffpost, * l’obs, * le monde diplomatique, * la société des lecteurs du monde, * talents, * source sûre, * le club de l’économie, * m publicité, * le carnet du monde,",
+ "newsletters du monde",
+ "recevoir les newsletters du monde",
+ "* sur iphone, * sur android,",
+ "archives du monde s’abonner se connecter consulter le journal du jour évenements abonnés jeux-concours abonnés contacter le monde",
+ "* mentions légales, * conditions générales, * charte du groupe, * politique de confidentialité, * aide (faq),",
+ "* mentions légales, * charte du groupe, * politique de confidentialité, * gestion des cookies, * conditions générales, * aide (faq),",
+ "suivez le monde",
+ "* facebook, * youtube, * twitter, * instagram, * snapchat, * fils rss,",
+ "ajouter à vos sélections",
+ "pour ajouter l’article à vos sélections identifiez-vous",
+ "s’inscrire gratuitement",
+ "vous possédez déjà un compte ?",
+ "se connecter",
+ "nos guides d’achat",
+ "services le monde",
+ "testez votre culture générale avec la rédaction du monde",
+ "mots croisés, sudoku, mots trouvés... jouez avec nous",
+ "gagnez du temps avec notre sélection des meilleurs produits",
+ "retrouvez nos derniers hors-séries, livres et unes du monde",
+ "le monde avec afp",
+ "affinez vos connaissances avec françoise barbe-gall, historienne de l’art.",
+ "le monde mémorable",
+ "temps de lecture 1 min.",
+ "les meilleurs boucleurs à cheveux",
+ "* imprimer l'article, * partager l'article sur facebook, * partager l'article sur twitter,",
+ "contenu sponsorisé",
+ "votre abonnement nous engage",
+ "en vous abonnant, vous soutenez le projet de la rédaction de marianne : un journalisme libre, ni partisan, ni pactisant, toujours engagé ; un journalisme à la fois critique et force de proposition.",
+ "natacha polony, directrice de la rédaction de marianne",
+ "découvrez le numéro de la semaine",
+ "lire le magazine",
+ "les articles les plus lus",
+ "le goût de la vérité n’empêche pas de prendre parti",
+ "albert camus",
+ "découvrir nos offres d’abonnement papier + numérique",
+ "le magazine",
+ "* déposer vos annonces légales, * voir nos annonces légales,",
+ "* foire aux questions, * mentions légales, * données personnelles et cookies, * cgu et cgv, * formulaire de rétractation, * postuler à un stage, * flux rss,",
+ "nos réseaux sociaux",
+ "facebook twitter",
+ "article abonné",
+ "je m'abonne pour 1€",
+ "default-output-block.skip-main",
+ "offre spéciale - s'abonner",
+ "* politique, * idées et débats, * monde, * climat et transitions, * economie, * tech et transformations, * entrepreneurs, * sciences et santé, * management, * education, * argent, * styles, * société, * culture,",
+ "l’express – codes promos",
+ "dellnikenocibé",
+ "adidasmaisons du monde",
+ "l’express franchiserénovation énergétique",
+ "l’express xiiengagés auprès des français",
+ "services de l’express",
+ "newsletterslire le magazinel'express audio",
+ "les podcasts de l’express",
+ "partager cet article",
+ "les plus lus",
+ "consommer de la viande rouge, est-ce mauvais pour la santé ?",
+ "la confir ...",
+ '"pourquoi la france est-elle si riche ?"',
+ ": la presse étrangère s’étonn ...",
+ 'jean-luc mélenchon, un "animal blessé" qui ourdit sa future candidatur ...',
+ 'bill browder, "l\'ennemi numéro un de poutine" : "je l’ai vu à l’œuvre, ...',
+ "homéopathie, naturopathie, médecines douces : l’étonnant lobbying du c ...",
+ '"oppenheimer" : son grand mérite, disculper albert einstein',
+ "par etienne klein*",
+ '"barbie" : ken, réveille-toi, ils sont devenus fous !',
+ "par abnousse shalmani",
+ "par christophe donner",
+ "sur le même thème",
+ "archives /2023202220212020201920182017201620152014201320122011",
+ "* tous nos dossiers, * podcast la loupe, * 70 ans l'express, * séries d'été, * l'express canada, * articles sport, * articles beauté, * articles people, * articles vie perso, * articles vie intime,",
+ "services partenaires",
+ "* entreprendre en franchise, * l'express codes promo, * investir en scpi avec corum l'epargne, * comparateur de mutuelles avec devisprox,",
+ "© l'express",
+ "* mentions légales, * cookies, * politique de confidentialité, * conditions générales d'utilisation, * qui sommes-nous?, * service client, * boutique, * régie publicitaire,",
+ "vous ne pouvez pas visionner ce contenu car :",
+ "* vous avez refusé les cookies associés aux contenus issus de tiers en vous abonnant.",
+ "vous ne pourrez donc pas lire nos vidéos qui ont besoin de cookies tiers pour fonctionner., * vous utilisez un bloqueur de publicité.",
+ "nous vous conseillons de le désactiver afin d’accéder à nos vidéos.,",
+ "si vous n'êtes dans aucun de ces deux cas, contactez-nous à aide@huffingtonpost.fr.",
+ "envoyer une correction",
+ "politique france international environnement life culture divertissement prise de parole vidéos jo paris 2024",
+ "les sites du groupe",
+ "courrier international",
+ "le monde diplomatique",
+ "suivez-nous",
+ "facebook instagram twitter youtube dailymotion flipboard newsletters rss",
+ "légal - infos",
+ "gestion des cookies qui sommes-nous ?",
+ "mentions légales conditions générales de vente politique de confidentialité publicité contactez nous faq plan du site",
+ "par le huffpost",
+ "le huffpost",
+ "par le huffpost avec afp",
+ "le huffpostafp",
+ "photo d’illustration.",
+ "julien de rosa / afp",
+ "(photo d’illustration)",
+ "franck fife / afp",
+ "andreas malm adapté au cinéma : comment saboter un film",
+ "emmanuel dunand / afp",
+ "ludovic marin / afp",
+ "voir la vidéo",
+ "miguel medina / afp",
+ "abonnez-vous 0,99€ le premier mois",
+ "covid : se revacciner vite ou attendre ?",
+ "l’avis des experts",
+ "des prigojine en puissance ?",
+ "en russie, les gouverneurs entrent en gue ...",
+ '"on pensait que c’était fini" : comment le covid rattrape les français ...',
+ '"elle va être ingérable" : sabrina agresti-roubache, le premier faux p ...',
+ "* nos applications mobiles, * suivre le figaro sur google actu, * le figaro nantes, * le figaro lyon, * le figaro bordeaux, * le figaro nice, * les vidéos figaro live, * les podcasts du figaro, * les programmes tv, * les résultats sportifs, * carnet du jour, * figaro store,",
+ "à voir également sur\xa0le huffpost\xa0:",
+ "à voir également sur le\xa0huffpost\xa0:",
+ "publié \n il y a 2 heures, \n mis à jour il y a 2 heures",
+ "mis à jour le",
+ "à voir aussi sur le huffpost\xa0:",
+ "publié \n il y a 1 heure, \n mis à jour il y a 1 heure",
+ "publié \n il y a 3 heures, \n mis à jour il y a 3 heures",
+ "à voir aussi sur\xa0le huffpost\xa0:",
+ "les infos à retenir",
+ "voir le produit",
+ "lorsque vous achetez via nos liens de vente, nous pouvons percevoir une commission d'affiliation.",
+ "(e.\xa0garnier/l'équipe)",
+ "les commentaires sont soumis à des règles de modération.",
+ "lire la charte",
+ "il n’y a pas encore de commentaire à cet article.",
+ "(a. martin/l'équipe)",
+ "(p.\xa0lahalle/l'équipe)",
+ "(n.\xa0luttiau/l'équipe)",
+ "(a. réau/l'équipe)",
+ "(s.\xa0boué/l'équipe)",
+ "(b.\xa0papon/l'équipe)",
+ "(f.\xa0faugère/l'équipe)",
+ "(a. mounic/l'équipe)",
+ "(s.\xa0mantey/l'équipe)",
+ "pas le temps de lire cet article ?",
+ "découvrez la lecture audio.",
+ "contenu conçu et proposé par le figaro services .",
+ ]
+ + [ # English Patterns
+ "skip past newsletter promotion sign up to first edition free daily newsletter archie bland and nimo omer take you through the top stories and what they mean, free every weekday morning privacy notice: newsletters may contain info about charities, online ads, and content funded by outside parties.",
+ "for more information see our newsletters may contain info about charities, online ads, and content funded by outside parties.",
+ "for more information see our privacy policy .",
+ "we use google recaptcha to protect our website and the google privacy policy and terms of service apply.",
+ "after newsletter promotion",
+ "sign up to newsletter",
+ "make a donation",
+ "skip past newsletter promotion sign up to business today free daily newsletter get set for the working day – we'll point you to all the business news and analysis you need every morning privacy notice: newsletters may contain info about charities, online ads, and content funded by outside parties.",
+ "if you buy something using links in our stories, we may earn a commission.",
+ "this helps support our journalism.",
+ "learn more.",
+ "image caption,",
+ "privacy notice: newsletters may contain info about charities, online ads, and content funded by outside parties.",
+ "previous slide",
+ "image source, getty images",
+ "we may earn a commission from links on this page.",
+ "advertisement",
+ "image source, reuters",
+ "subscriptions",
+ "image source, pa media",
+ "get more from wired",
+ "all rights reserved.",
+ "skip to main content",
+ "to revisit this article, select my account, then view saved stories",
+ "to revisit this article, visit my profile, then view saved stories",
+ "find anything you save across the site in your account",
+ "new yorker favorites",
+ "sign up for our daily newsletter to receive the best stories from the new yorker.",
+ "© 2023 condé nast.",
+ "use of this site constitutes acceptance of our user agreement and privacy policy and cookie statement and your california privacy rights.",
+ "the new yorker may earn a portion of sales from products that are purchased through our site as part of our affiliate partnerships with retailers.",
+ "the material on this site may not be reproduced, distributed, transmitted, cached or otherwise used, except with the prior written permission of condé nast.",
+ "a reporter at large",
+ "* the onion, * the a.v.",
+ "club, * deadspin, * gizmodo, * jalopnik, * jezebel, * kotaku, * quartz, * the root, * the takeout, * the inventory,",
+ "america's finest news source.",
+ "send us a tip!shopsubscribe",
+ "* off, * english,",
+ "share this video",
+ "facebooktwitteremail",
+ "to revist this article, visit my profile, then view saved stories.",
+ "* backchannel, * business, * culture, * gear, * ideas, * science, * security,",
+ "* podcasts, * video, * artificial intelligence, * climate, * games, * newsletters, * magazine, * events, * wired insider, * jobs, * coupons,",
+ "most popular",
+ "this site is protected by recaptcha and the google privacy policy and terms of service apply.",
+ "by signing up, you agree to our user agreement and privacy policy & cookie statement.",
+ "our flagship newsletter highlights the best of the new yorker, including top stories, fiction, humor, and podcasts.",
+ "e-mail address",
+ "more from wired",
+ "wired is where tomorrow is realized.",
+ "it is the essential source of information and ideas that make sense of a world in constant transformation.",
+ "the wired conversation illuminates how technology is changing every aspect of our lives—from culture to business, science to design.",
+ "the breakthroughs and innovations that we uncover lead to new ways of thinking, new connections, and new industries.",
+ "wired may earn a portion of sales from products that are purchased through our site as part of our affiliate partnerships with retailers.",
+ "select international site",
+ "* uk, * italia, * japón,",
+ "please also consider subscribing to wired",
+ "subscribe now",
+ "view introductory offers",
+ "no commitment, cancel anytime*",
+ "offer ends 14th june 2023.",
+ "*cancel anytime within 14 days of payment to receive a refund on unserved issues.",
+ "inclusive of applicable taxes (vat)",
+ "existing subscribers",
+ "sign in to your account",
+ "more from new scientist",
+ "explore the latest news, articles and features",
+ "subscriber-only",
+ "popular articles",
+ "trending new scientist articles",
+ "download the app",
+ "find us on social media",
+ "* instagram, * facebook, * twitter, * tiktok, * linkedin,",
+ "* subscriber benefits, * gift, * student, * educational, * corporate,",
+ "* help, * about us, * advertise, * write for us,",
+ "* events, * science jobs, * colab, * syndication, * rss feeds,",
+ "legal and privacy",
+ "* contact us, * privacy policy, * cookie policy, * terms & conditions,",
+ "© copyright new scientist ltd.",
+ "skip to main contentskip to navigationskip to navigation",
+ "print subscriptions",
+ "search jobs",
+ "* international edition, * uk edition, * us edition, * australia edition,",
+ "the guardian - back to homethe guardian",
+ "* world, * europe, * us, * americas, * asia, * australia, * middle east, * africa, * inequality, * global development,",
+ "skip past newsletter promotion",
+ "free daily newsletter",
+ "for more information see our privacy policy.",
+ "reuse this content",
+ "more on this story",
+ "most viewed",
+ "* news, * opinion, * sport, * culture, * lifestyle,",
+ "original reporting and incisive analysis, direct from the guardian every morning",
+ "sign up for our email",
+ "* help, * complaints & corrections, * securedrop, * work for us, * privacy policy, * cookie policy, * terms & conditions, * contact us,",
+ "* all topics, * all writers, * digital newspaper archive, * facebook, * youtube, * instagram, * linkedin, * twitter, * newsletters,",
+ "* advertise with us, * search uk jobs,",
+ "back to top",
+ "© 2023 guardian news & media limited or its affiliated companies.",
+ "* books, * music, * tv & radio, * art & design, * film, * games, * classical, * stage,",
+ "* published1 hour ago,",
+ "about sharing",
+ "related topics",
+ "top stories",
+ "elsewhere on the bbc",
+ "* home, * news, * sport, * reel, * worklife, * travel, * future, * culture, * music, * tv, * weather, * sounds,",
+ "* terms of use, * about the bbc, * privacy policy, * cookies, * accessibility help, * parental guidance, * contact the bbc, * get personalised newsletters, * why you can trust the bbc, * advertise with us,",
+ "â© 2023 bbc.",
+ "the bbc is not responsible for the content of external sites.",
+ "read about our approach to external linking.",
+ "media caption,",
+ "* published2 hours ago,",
+ "* published5 hours ago,",
+ "* published3 hours ago,",
+ "explore more",
+ "editor's recommendations",
+ "accessibility links",
+ "* skip to content, * accessibility help,",
+ "bbc account",
+ "notifications",
+ "search bbc search bbc",
+ "bbcsportall sport",
+ "also in sport",
+ "explore the bbc",
+ "* terms of use, * about the bbc, * privacy policy, * privacy policy, * cookies, * cookies, * accessibility help, * parental guidance, * contact the bbc, * make an editorial complaint, * bbc emails for you, * advertise with us,",
+ "copyright © 2023 bbc.",
+ "explore hbr",
+ "* tweet, * post, * share, * annotate, * save, * print,",
+ "* uk, * uk politics, * education, * media, * society, * law, * scotland, * wales, * northern ireland,",
+ "sign up to business today",
+ "get set for the working day – we'll point you to all the business news and analysis you need every morning",
+ "free weekly newsletter",
+ "* business, * economics, * banking, * money, * markets, * project syndicate, * b2b, * retail,",
+ "* world, * uk, * climate crisis, * environment, * science, * global development, * football, * tech, * business, * obituaries,",
+ "* money, * property, * pensions, * savings, * borrowing, * careers,",
+ "support the guardian",
+ "related internet links",
+ "* how to follow your premier league team on the bbceverything you need to know to make sure you never miss a moment., * today's football gossipthe latest rumours and stories from around the world of football., * phil mcnultyanalysis and opinion from our chief football writer., * how to get into footballhow to get into football - the most popular sport in the world, with clubs and facilities throughout the uk.,",
+ "from other local news sites",
+ "information about bbc links to other news sites",
+ "join the conversation",
+ "* the great resignation is over, say experts, * the protectors of a 7,000-year-old faith, * what colour should you wear in the heat?,",
+ "now playing",
+ "* the world's largest landlocked country, * which is the best sleeping position?, * the 'npc' trend sweeping tiktok,",
+ "* the new napoleon film stirring debate, * stunning photos of a new african wonder, * why electric crops may soon be on the menu,",
+ "- source:\n cnn",
+ ]
+ + [ # Dutch Patterns
+ "heeft u vragen, suggesties of ideeën over onze journalistiek?",
+ "mail dan naar onze ombudsman via ombudsman@nrc.nl.",
+ "goedemorgen!",
+ "ga je de weg op?",
+ "hier vind je het overzicht van de werkzaamheden.",
+ "rtv utrecht",
+ "omroep gelderland",
+ "lezers zijn de auteurs van deze rubriek.",
+ "insturen via ik@nrc.nl",
+ "omroep brabant",
+ "omroep zeeland",
+ "lees ze hier terug.",
+ "omroep flevoland",
+ "kopieer de link van het artikel",
+ "best gelezen",
+ "instellingen",
+ "* mijn account, * inloggenu bent niet ingelogd, * uitloggen,",
+ "personaliseren",
+ "* meldingen, * nieuwsbrieven, * mijn nieuwsbrieven, * data en privacydata en privacyprivacy-instellingencookiebeleidprivacy,",
+ "* digitale krant, * winkel, * puzzels,",
+ "vragen & contact",
+ "* klantenservice, * tip de redactie, * familieberichten plaatsen, * wat vindt u van deze website?, * gebruiksvoorwaarden,",
+ "* digitale editie, * puzzels,",
+ "* cultuur&media, * duurzaamheid&economie, * opinie, * podcasts, * politiek, * puzzels, * recepten, * religie&filosofie, * sport, * tijdgeest, * verdieping, * wetenschap,",
+ "wilt u iets delen met trouw?",
+ "tip hier onze journalisten",
+ "* over ons, * contact met trouw, * privacystatement, * abonnementsvoorwaarden, * gebruiksvoorwaarden, * cookiebeleid, * privacy-instellingen, * auteursrecht, * colofon,",
+ "* klantenservice, * mijn omgeving, * vakantieservice, * adverteren, * losse verkoop,",
+ "* abonneren, * nieuwsbrieven, * digitale krant, * webwinkel, * rss-feeds, * facebook, * twitter, * android apps, * ios apps,",
+ "* columnisten, * recensies, * archief,",
+ "op alle verhalen van trouw rust uiteraard copyright.",
+ "wil je tekst overnemen of een video(fragment), foto of illustratie gebruiken, mail dan naar copyright@trouw.nl.",
+ "© 2023 dpg media b.v. - alle rechten voorbehouden",
+ "meer buitenland",
+ "abonneren mijn nieuws podcasts digitale krant",
+ "neem een abonnement",
+ "mijn nieuws mijn leeslijst mijn geschiedenis digitale krant",
+ "nieuwsbrieven onderwerpen",
+ "ik ben abonnee neem een abonnement",
+ "privacy-instellingen notificaties",
+ "bezorgservice vakantieservice verhuisservice mijn gegevens mijn abonnementen abonnement delen gedeeld abonnement faq digitaal lezen veelgestelde vragen wachtwoord vergeten",
+ "terug naar de krant",
+ "al abonnee?",
+ "het kan zijn dat elementen ontbreken aan deze printversie.",
+ "luister meer...",
+ "leestijd 2 minuten",
+ "meld een taalfout",
+ "toevoegen aan",
+ "+ verzameling",
+ "lees ook deze artikelen",
+ "* over nrc, * over ons, * werken bij, * auteursrecht, * privacy, * leveringsvoorwaarden, * nrc-code, * onze app, * archief, * adverteren,",
+ "* mijn nrc, * neem een abonnement, * inloggen, * account aanmaken, * digitale krant, * mijn leeslijst, * mijn abonnementen, * service & bezorging, * nieuwsbrieven,",
+ "* contact, * redactie, * opinieredactie, * de ombudsman, * colofon, * adsales, * klantenservice, * familieberichten,",
+ "* nrc websites, * mediahuis nrc, * nrc carrière, * nrc webwinkel, * nrc lezersfonds,",
+ "leestijd 3 minuten",
+ "leestijd 1 minuut",
+ "* ga naar het menu, * ga naar de inhoud,",
+ "deel artikel:",
+ "advertentie via ster.nl",
+ "tip de redactiegeef je tips aan ons door",
+ "publieksvoorlichtingvoor vragen en reacties",
+ "nos informatie",
+ "* over de nos, * werken bij de nos, * contact, * journalistieke verantwoording, * herstelrubriek, * ombudsman npo, * nos apps, * voorwaarden, * privacy,",
+ "* voorpagina, * laatste nieuws, * video's, * binnenland, * buitenland, * regionaal nieuws, * politiek, * economie, * koningshuis, * tech, * cultuur & media, * opmerkelijk, * archief,",
+ "* voorpagina, * video's, * voetbal, * formule 1, * wielrennen, * schaatsen, * tennis, * archief,",
+ "© nos 2023cookie-instellingen",
+ "in samenwerking met",
+ "* buitenland,",
+ "* binnenland,",
+ "omrop fryslân",
+ "omroep west",
+ "rtv drenthe",
+ "en hier zie je waar wordt gewerkt aan het spoor.",
+ "een ikje is een persoonlijke ervaring of anekdote in maximaal 120 woorden.",
+ "redacteur online",
+ "redacteur tech",
+ "nando kasteleijn",
+ "redacteur economie",
+ "redacteur buitenland",
+ "redacteur binnenland",
+ "oorlog hamas-israël",
+ "u kunt ons met dit formulier daarover informeren, dat stellen wij zeer op prijs.",
+ "berichten over andere zaken dan taalfouten of feitelijke onjuistheden worden niet gelezen.",
+ "taalfout of feitelijke onjuistheid (maximaal 120 woorden)",
+ "maximaal 120 woorden a.u.b.",
+ "e-mailadres",
+ "vul een correct e-mail adres in",
+ "© 2024 dpg media b.v. - alle rechten voorbehouden",
+ "geselecteerd door de redactie",
+ "twitter bericht wordt geladen...",
+ ]
+)
+
JUNK_PREFIXES = [
"Der er ikke oplæsning af denne artikel, så den oplæses derfor med maskinstemme."
]
@@ -39,8 +1118,66 @@
"""
print("-------->>>>> at the beginning of content_cleaner.py")
+
+
+def normalize_sent(text: str):
+ return text.lower().strip()
+
+
+def filter_noise_patterns(article, sent_filter_set, crawl_report=None, feed=None, url=None):
+ clean_artcile = ""
+ for paragraph in article.split("\n\n"):
+ clean_paragraph = ""
+ is_prev_skip = False
+ for sent in sent_tokenize(paragraph):
+ if is_prev_skip and len(sent) <= 10:
+ print("Skipped (Prev Skipped and Short!): ", sent)
+ if crawl_report is not None:
+ crawl_report.add_sent_removed(feed, sent, url)
+ continue
+ else:
+ is_prev_skip = False
+ if normalize_sent(sent) in sent_filter_set:
+ print("Skipped (Repetitive): ", sent)
+ if crawl_report is not None:
+ crawl_report.add_sent_removed(feed, sent, url)
+ is_prev_skip = True
+ continue
+ clean_paragraph += sent + " "
+ if len(clean_paragraph) < 10:
+ continue
+ clean_artcile += clean_paragraph + "\n\n"
+ return clean_artcile.strip()
+
+
+def cleanup_non_content_bits_w_crawl_report(text: str, crawl_report, feed, url) -> str:
+ new_text = text
+ new_text = filter_noise_patterns(
+ text, set(JUNK_COUNT_PATTERNS), crawl_report, feed, url
+ )
+ for junk_pattern in JUNK_PATTERNS_TO_REMOVE:
+ cleaned = new_text.replace(junk_pattern, "")
+
+ if cleaned != new_text:
+ crawl_report.add_sent_removed(feed, junk_pattern, url)
+ print(f"- cleaned: {junk_pattern}")
+ new_text = cleaned
+
+ clean_text = ""
+ for junk_prefix in JUNK_PREFIXES:
+ for each in new_text.split("\n"):
+ if each.startswith(junk_prefix):
+ print(">>>> dropping the Paragraph: " + each)
+ crawl_report.add_sent_removed(feed, junk_pattern, url)
+ continue
+ clean_text += each + "\n"
+
+ return clean_text
+
+
def cleanup_non_content_bits(text: str):
new_text = text
+ new_text = filter_noise_patterns(text, set(JUNK_COUNT_PATTERNS))
for junk_pattern in JUNK_PATTERNS_TO_REMOVE:
cleaned = new_text.replace(junk_pattern, "")
diff --git a/zeeguu/core/content_quality/quality_filter.py b/zeeguu/core/content_quality/quality_filter.py
index aa1c8ef3..e14ef84e 100644
--- a/zeeguu/core/content_quality/quality_filter.py
+++ b/zeeguu/core/content_quality/quality_filter.py
@@ -1,5 +1,5 @@
import newspaper
-from zeeguu.core.model import Article
+from zeeguu.core.model import Article, LowQualityTypes
from zeeguu.core.ml_models import is_paywalled, ID_TO_LABEL_PAYWALL
HTML_READ_MORE_PATTERNS = [
@@ -41,41 +41,58 @@ def sufficient_quality_html(html):
return (
False,
f"Incomplete Article (based on HTML analysis). Contains: {each}",
+ LowQualityTypes.HTML_PATTERN,
)
- return True, ""
+ return True, "", ""
def sufficient_quality_plain_text(text):
word_count = len(text.split())
if word_count < Article.MINIMUM_WORD_COUNT:
- return False, f"Too Short ({word_count} words) {text}"
+ return (
+ False,
+ f"Too Short ({word_count} words) {text}",
+ LowQualityTypes.TOO_SHORT,
+ )
for each in PLAIN_TEXT_PAYWALL_PATTERNS:
if text.find(each) >= 0:
- return False, f"Incomplete pattern in text: {each}"
+ return (
+ False,
+ f"Incomplete pattern in text: {each}",
+ LowQualityTypes.TEXT_PAYWALL_PATTERN,
+ )
if text.endswith(incomplete_suggesting_terminations):
- return False, 'Ends with "Read More" or similar'
+ return (
+ False,
+ 'Ends with "Read More" or similar',
+ LowQualityTypes.INCOMPLETE_PATTERN,
+ )
for each in LIVE_BLOG_KIND_OF_PATTERNS:
if text.find(each) >= 0:
- return False, "Live blog kind of article"
+ return False, "Live blog kind of article", LowQualityTypes.LIVE_BLOG
paywall_pred = is_paywalled(text)
if paywall_pred > 0:
# 0 is Normal Text
label_found = ID_TO_LABEL_PAYWALL[paywall_pred]
- return False, f"ML Prediction was '{label_found}'."
+ return (
+ False,
+ f"ML Prediction was '{label_found}'.",
+ LowQualityTypes.ML_PREDICTION,
+ )
- return True, ""
+ return True, "", ""
-def sufficient_quality(art: newspaper.Article) -> (bool, str):
- res, reason = sufficient_quality_html(art.html)
+def sufficient_quality(art: newspaper.Article) -> tuple[bool, str, str]:
+ res, reason, code = sufficient_quality_html(art.html)
if not res:
- return False, reason
- res, reason = sufficient_quality_plain_text(art.text)
+ return False, reason, code
+ res, reason, code = sufficient_quality_plain_text(art.text)
if not res:
- return False, reason
+ return False, reason, code
- return True, ""
+ return True, "", ""
diff --git a/zeeguu/core/content_retriever/__init__.py b/zeeguu/core/content_retriever/__init__.py
index 58a79367..70d300a5 100644
--- a/zeeguu/core/content_retriever/__init__.py
+++ b/zeeguu/core/content_retriever/__init__.py
@@ -1,4 +1,4 @@
-from zeeguu.core.content_cleaning import cleanup_text
+from zeeguu.core.content_cleaning import cleanup_text, cleanup_text_w_crawl_report
def download_and_parse(url):
@@ -8,3 +8,14 @@ def download_and_parse(url):
np_article.text = cleanup_text(np_article.text)
return np_article
+
+
+def download_and_parse_with_remove_sents(url, crawl_report, feed):
+ from .parse_with_readability_server import download_and_parse as _download_and_parse
+
+ np_article = _download_and_parse(url)
+ np_article.text = cleanup_text_w_crawl_report(
+ np_article.text, crawl_report, feed, url
+ )
+
+ return np_article
diff --git a/zeeguu/core/content_retriever/article_downloader.py b/zeeguu/core/content_retriever/article_downloader.py
index f2c6d2e1..40dfcfa0 100644
--- a/zeeguu/core/content_retriever/article_downloader.py
+++ b/zeeguu/core/content_retriever/article_downloader.py
@@ -7,7 +7,8 @@
"""
import newspaper
-
+from collections import Counter
+from time import time
from pymysql import DataError
from zeeguu.core.content_retriever.crawler_exceptions import *
@@ -24,7 +25,9 @@
from sentry_sdk import capture_exception as capture_to_sentry
from zeeguu.core.elastic.indexing import index_in_elasticsearch
-from zeeguu.core.content_retriever import download_and_parse
+from zeeguu.core.content_retriever import (
+ download_and_parse_with_remove_sents,
+)
TIMEOUT_SECONDS = 10
@@ -56,7 +59,9 @@ def banned_url(url):
return False
-def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
+def download_from_feed(
+ feed: Feed, session, crawl_report, limit=1000, save_in_elastic=True
+):
"""
Session is needed because this saves stuff to the DB.
@@ -70,7 +75,7 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
"""
summary_stream = ""
-
+ start_feed_time = time()
downloaded = 0
downloaded_titles = []
skipped_due_to_low_quality = 0
@@ -90,12 +95,11 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
traceback.print_stack()
capture_to_sentry(e)
- return
+ return ""
+ skipped_already_in_db = 0
for feed_item in items:
- skipped_already_in_db = 0
-
if downloaded >= limit:
break
@@ -109,8 +113,10 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
feed_item_timestamp > last_retrieval_time_seen_this_crawl
):
last_retrieval_time_seen_this_crawl = feed_item_timestamp
+ crawl_report.set_feed_last_article_date(feed, feed_item_timestamp)
if last_retrieval_time_seen_this_crawl > feed.last_crawled_time:
+ crawl_report.set_feed_last_article_date(feed, feed_item_timestamp)
feed.last_crawled_time = last_retrieval_time_seen_this_crawl
session.add(feed)
session.commit()
@@ -124,7 +130,6 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
continue
try:
-
url = _url_after_redirects(feed_item["url"])
# check if the article after resolving redirects is already in the DB
@@ -146,9 +151,15 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
continue
try:
- new_article = download_feed_item(session, feed, feed_item, url)
+ new_article = download_feed_item(
+ session,
+ feed,
+ feed_item,
+ url,
+ crawl_report,
+ )
downloaded += 1
- if save_in_elastic:
+ if save_in_elastic and not new_article.broken:
if new_article:
index_in_elasticsearch(new_article, session)
@@ -198,7 +209,11 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
else:
logp(e)
continue
-
+ crawl_report.set_feed_total_articles(feed, len(items))
+ crawl_report.set_feed_total_downloaded(feed, downloaded)
+ crawl_report.set_feed_total_low_quality(feed, skipped_due_to_low_quality)
+ crawl_report.set_feed_total_in_db(feed, skipped_already_in_db)
+ crawl_report.set_feed_crawl_time(feed, round(time() - start_feed_time, 2))
summary_stream += (
f"{downloaded} new articles from {feed.title} ({len(items)} items)\n"
)
@@ -209,11 +224,12 @@ def download_from_feed(feed: Feed, session, limit=1000, save_in_elastic=True):
logp(f"*** Low Quality: {skipped_due_to_low_quality}")
logp(f"*** Already in DB: {skipped_already_in_db}")
logp(f"*** ")
+ session.commit()
return summary_stream
-def download_feed_item(session, feed, feed_item, url):
+def download_feed_item(session, feed, feed_item, url, crawl_report):
title = feed_item["title"]
published_datetime = feed_item["published_datetime"]
@@ -223,12 +239,9 @@ def download_feed_item(session, feed, feed_item, url):
if art:
raise SkippedAlreadyInDB()
- np_article = download_and_parse(url)
+ np_article = download_and_parse_with_remove_sents(url, crawl_report, feed)
- is_quality_article, reason = sufficient_quality(np_article)
-
- if not is_quality_article:
- raise SkippedForLowQuality(reason)
+ is_quality_article, reason, code = sufficient_quality(np_article)
summary = feed_item["summary"]
# however, this is not so easy... there have been cases where
@@ -257,14 +270,23 @@ def download_feed_item(session, feed, feed_item, url):
feed.language,
htmlContent=np_article.htmlContent,
)
+ session.add(new_article)
+
+ if not is_quality_article:
+ MAX_WORD_FOR_BROKEN_ARTICLE = 10000
+ crawl_report.add_non_quality_reason(feed, code, str(url))
+ new_article.set_as_broken(session, code)
+ if len(new_article.content.split()) > MAX_WORD_FOR_BROKEN_ARTICLE:
+ new_article.content = new_article.content[:MAX_WORD_FOR_BROKEN_ARTICLE]
+ session.add(new_article)
+ raise SkippedForLowQuality(reason)
if np_article.top_image != "":
new_article.img_url = Url.find_or_create(session, np_article.top_image)
- session.add(new_article)
topics = add_topics(new_article, session)
logp(f" Topics ({topics})")
-
+ session.add(new_article)
return new_article
diff --git a/zeeguu/core/model/__init__.py b/zeeguu/core/model/__init__.py
index c92932a7..136b16ae 100644
--- a/zeeguu/core/model/__init__.py
+++ b/zeeguu/core/model/__init__.py
@@ -35,6 +35,7 @@
from .user_preference import UserPreference
from .session import Session
from .unique_code import UniqueCode
+from .article_broken_code_map import ArticleBrokenMap, LowQualityTypes
from .user_language import UserLanguage
diff --git a/zeeguu/core/model/article.py b/zeeguu/core/model/article.py
index f751d153..ec0e3380 100644
--- a/zeeguu/core/model/article.py
+++ b/zeeguu/core/model/article.py
@@ -276,6 +276,15 @@ def is_owned_by(self, user):
def add_topic(self, topic):
self.topics.append(topic)
+ def set_as_broken(self, session, broken_code):
+ from zeeguu.core.model.article_broken_code_map import ArticleBrokenMap
+
+ article_broken_map = ArticleBrokenMap.find_or_create(session, self, broken_code)
+ self.broken = True
+ session.add(article_broken_map)
+ session.add(self)
+ session.commit()
+
def add_search(self, search):
self.searches.append(search)
@@ -309,7 +318,7 @@ def update_content(self, session):
sufficient_quality_plain_text,
)
- quality, reason = sufficient_quality_plain_text(self.content)
+ quality, reason, _ = sufficient_quality_plain_text(self.content)
if not quality:
print("Marking as broken. Reason: " + reason)
self.mark_as_low_quality_and_remove_from_index()
diff --git a/zeeguu/core/model/article_broken_code_map.py b/zeeguu/core/model/article_broken_code_map.py
new file mode 100644
index 00000000..50df854c
--- /dev/null
+++ b/zeeguu/core/model/article_broken_code_map.py
@@ -0,0 +1,57 @@
+from sqlalchemy import PrimaryKeyConstraint
+from sqlalchemy.orm import relationship
+from zeeguu.core.model.article import Article
+
+import sqlalchemy
+
+from zeeguu.core.model import db
+
+
+class LowQualityTypes:
+ TOO_SHORT = "TOO_SHORT"
+ HTML_PATTERN = "HTML_PATTERN"
+ TEXT_PAYWALL_PATTERN = "PAYWALL_PATTERN"
+ INCOMPLETE_PATTERN = "INCOMPLETE_PATTERN"
+ LIVE_BLOG = "LIVE_BLOG"
+ ML_PREDICTION = "ML_PREDICTION"
+
+
+class ArticleBrokenMap(db.Model):
+ """
+ When an article is set as broken, then we pass a reason on why it was marked
+ as broken.
+ """
+
+ __tablename__ = "article_broken_code_map"
+
+ article_id = db.Column(db.Integer, db.ForeignKey(Article.id))
+ article = relationship(Article)
+
+ broken_code = db.Column(db.UnicodeText)
+ __table_args__ = (
+ PrimaryKeyConstraint(article_id, broken_code),
+ {"mysql_collate": "utf8_bin"},
+ )
+
+ def __init__(self, article: Article, broken_code: LowQualityTypes):
+ self.article = article
+ self.broken_code = broken_code
+
+ def __str__(self):
+ return f"Article ({self.article_id}, broken: '{self.broken_code}')"
+
+ __repr__ = __str__
+
+ @classmethod
+ def find_or_create(cls, session, article, broken_code):
+ try:
+ return (
+ cls.query.filter(cls.article == article)
+ .filter(cls.broken_code == broken_code)
+ .one()
+ )
+ except sqlalchemy.orm.exc.NoResultFound:
+ new = cls(article, broken_code)
+ session.add(new)
+ session.commit()
+ return new
diff --git a/zeeguu/core/test/test_feed.py b/zeeguu/core/test/test_feed.py
index b15231fd..e5c2c117 100644
--- a/zeeguu/core/test/test_feed.py
+++ b/zeeguu/core/test/test_feed.py
@@ -7,16 +7,19 @@
from zeeguu.core.test.rules.feed_rule import FeedRule
from zeeguu.core.content_retriever.article_downloader import download_from_feed
from zeeguu.core.feed_handler import FEED_TYPE
+from tools.crawl_summary.crawl_report import CrawlReport
class FeedTest(ModelTestMixIn, TestCase):
def setUp(self):
super().setUp()
-
+ self.crawl_report = CrawlReport()
self.spiegel = FeedRule().feed1
self.newspaper_da = FeedRule().feed_newspaper_da
- download_from_feed(self.spiegel, db.session, 3, False)
- download_from_feed(self.newspaper_da, db.session, 3, False)
+ self.crawl_report.add_feed(self.spiegel)
+ self.crawl_report.add_feed(self.newspaper_da)
+ download_from_feed(self.spiegel, db.session, self.crawl_report, 3, False)
+ download_from_feed(self.newspaper_da, db.session, self.crawl_report, 3, False)
def test_feed_items(self):
assert len(self.spiegel.get_articles()) == 2
diff --git a/zeeguu/core/test/test_retrieve_and_compute.py b/zeeguu/core/test/test_retrieve_and_compute.py
index 2e9055e6..e3e4c8cb 100644
--- a/zeeguu/core/test/test_retrieve_and_compute.py
+++ b/zeeguu/core/test/test_retrieve_and_compute.py
@@ -7,8 +7,12 @@
from zeeguu.core.test.rules.user_rule import UserRule
from zeeguu.core.content_cleaning.content_cleaner import cleanup_non_content_bits
from zeeguu.core.content_retriever.article_downloader import download_from_feed
-from zeeguu.core.content_quality.quality_filter import sufficient_quality
+from zeeguu.core.content_quality.quality_filter import (
+ sufficient_quality,
+ LowQualityTypes,
+)
from zeeguu.core.model import Topic, LocalizedTopic
+from tools.crawl_summary.crawl_report import CrawlReport
from zeeguu.core.test.mocking_the_web import *
@@ -22,7 +26,9 @@ def setUp(self):
def testDifficultyOfFeedItems(self):
feed = FeedRule().feed1
- download_from_feed(feed, zeeguu.core.model.db.session, 3, False)
+ crawl_report = CrawlReport()
+ crawl_report.add_feed(feed)
+ download_from_feed(feed, zeeguu.core.model.db.session, crawl_report, 3, False)
articles = feed.get_articles(limit=2)
@@ -37,8 +43,9 @@ def testDownloadWithTopic(self):
loc_topic = LocalizedTopic(topic, self.lan, "spiegelDE", "spiegel")
zeeguu.core.model.db.session.add(loc_topic)
zeeguu.core.model.db.session.commit()
-
- download_from_feed(feed, zeeguu.core.model.db.session, 3, False)
+ crawl_report = CrawlReport()
+ crawl_report.add_feed(feed)
+ download_from_feed(feed, zeeguu.core.model.db.session, crawl_report, 3, False)
article = feed.get_articles(limit=2)[0]
@@ -49,14 +56,14 @@ def test_sufficient_quality(self):
art.download()
art.parse()
- assert sufficient_quality(art)
+ assert sufficient_quality(art)[0]
def test_new_scientist_overlay(self):
art = newspaper.Article(URL_NEWSCIENTIST_FISH)
art.download()
art.parse()
- is_quality, _ = sufficient_quality(art)
+ is_quality, _, _ = sufficient_quality(art)
assert not is_quality
def test_le_monde_subscription(self):
@@ -64,7 +71,7 @@ def test_le_monde_subscription(self):
art.download()
art.parse()
- is_quality, _ = sufficient_quality(art)
+ is_quality, _, _ = sufficient_quality(art)
assert not is_quality
def test_fragment_removal(self):
@@ -74,10 +81,11 @@ def test_fragment_removal(self):
cleaned_up_text = cleanup_non_content_bits(art.text)
assert "Advertisement" not in cleaned_up_text
-
+
def test_ml_classification(self):
db_content = mock_readability_call(URL_ML_JP_PAYWALL)
- is_quality, reason = sufficient_quality(db_content)
+ is_quality, reason, code = sufficient_quality(db_content)
assert not is_quality
assert reason == "ML Prediction was 'Paywalled'."
+ assert code == LowQualityTypes.ML_PREDICTION