Examples and Tutorials
1. Building and Crawling a News Sources using a Multithreaded approach
Building and crawling news websites can require the handling of multiple sources simultaneously and processing a large volume of articles. You can significantly improve the performance of this process by using multiple threads when crawling. Even if Python is not truly multithreaded (due to the GIL), i/o requests can be handled in parallel.
from newspaper import Source
from newspaper.mthreading import fetch_news
import threading
class NewsCrawler:
def __init__(self, source_urls, config=None):
self.sources = [Source(url, config=config) for url in source_urls]
self.articles = []
def build_sources(self):
# Multithreaded source building
threads = [threading.Thread(target=source.build) for source in self.sources]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
def crawl_articles(self):
# Multithreaded article downloading
self.articles = fetch_news(self.sources, threads=4)
def extract_information(self):
# Extract information from each article
for source in self.sources:
print(f"Source {source.url}")
for article in source.articles[:10]:
article.parse()
print(f"Title: {article.title}")
print(f"Authors: {article.authors}")
print(f"Text: {article.text[:150]}...") # Printing first 150 characters of text
print("-------------------------------")
if __name__ == "__main__":
source_urls = ['https://slate.com', 'https://time.com'] # Add your news source URLs here
crawler = NewsCrawler(source_urls)
crawler.build_sources()
crawler.crawl_articles()
crawler.extract_information()
2. Getting Articles with Scrapy
Install Necessary Packages
pip install scrapy
pip install newspaper4k
Create the scrapy project:
scrapy startproject news_scraper
This command creates a new folder news_scraper with the necessary Scrapy files.
Code the Scrapy Spider
Navigate to the news_scraper/spiders folder and create a new spider. For example, news_spider.py:
import scrapy import newspaper class NewsSpider(scrapy.Spider): name = 'news' start_urls = ['https://abcnews.go.com/elections'] # Replace with your target URLs def parse(self, response): # Extract URLs from the response and yield Scrapy Requests for href in response.css('a::attr(href)'): yield response.follow(href, self.parse_article) def parse_article(self, response): # Use Newspaper4k to parse the article article = newspaper.article(response.url, language='en', input_html=response.text) article.parse() article.nlp() # Extracted information yield { 'url': response.url, 'title': article.title, 'authors': article.authors, 'text': article.text, 'publish_date': article.publish_date, 'keywords': article.keywords, 'summary': article.summary, }
Run the Spider
scrapy crawl news -o output.json
3. Using Playwright to Scrape Websites built with Javascript
Install Necessary Packages
pip install newspaper4k
pip install playwright
playwright install
Scrape with Playwright
from playwright.sync_api import sync_playwright
import newspaper
import time
def scrape_with_playwright(url):
# Using Playwright to render JavaScript
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
time.sleep(1) # Allow the javascript to render
content = page.content()
browser.close()
# Using Newspaper4k to parse the page content
article = newspaper.article(url, input_html=content, language='en')
return article
# Example URL
url = 'https://ec.europa.eu/commission/presscorner/detail/en/ac_24_84' # Replace with the URL of your choice
# Scrape and process the article
article = scrape_with_playwright(url)
article.nlp()
print(f"Title: {article.title}")
print(f"Authors: {article.authors}")
print(f"Publication Date: {article.publish_date}")
print(f"Summary: {article.summary}")
print(f"Keywords: {article.keywords}")
4. Using Playwright to Scrape Websites that require login
from playwright.sync_api import sync_playwright
import newspaper
def login_and_fetch_article(url, login_url, username, password):
# Using Playwright to handle login and fetch article
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # Set headless=False to watch the browser actions
page = browser.new_page()
# Automating login
page.goto(login_url)
page.fill('input[name="log"]', username) # Adjust the selector as per the site's HTML
page.fill('input[name="pwd"]', password) # Adjust the selector as per the site's HTML
page.click('input[type="submit"][value="Login"]') # Adjust the selector as per the site's HTML
# Wait for navigation after login
page.wait_for_url('/')
# Navigating to the article
page.goto(url)
content = page.content()
browser.close()
# Using Newspaper4k to parse the page content
article = newspaper.article(url, input_html=content, language='en')
return article
# Example URLs and credentials
login_url = 'https://www.undercurrentnews.com/login/' # Replace with the actual login URL
article_url = 'https://www.undercurrentnews.com/2024/01/08/editors-choice-farmed-shrimp-output-to-drop-in-2024-fallout-from-us-expanded-russia-ban/' # Replace with the URL of the article you want to scrape
username = 'tester_news' # Replace with your username
password = 'test' # Replace with your password
# Fetch and process the article
article = login_and_fetch_article(article_url, login_url, username, password)
article.nlp()
print(f"Title: {article.title}")
print(f"Authors: {article.authors}")
print(f"Publication Date: {article.publish_date}")
print(f"Summary: {article.summary}")
print(f"Keywords: {article.keywords}")
5. Setting a Custom User-Agent and Using fake-useragent
Some news websites block requests that use the default user-agent string. You can set a
custom user-agent via the browser_user_agent parameter to make your requests look like
a regular browser visit.
Simple Custom User-Agent
Pass browser_user_agent directly to newspaper.article, Article, or
newspaper.build:
import newspaper
from newspaper import Article, Source
user_agent = (
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/50.0.2661.102 Safari/537.36'
)
# Using the shortcut function
article = newspaper.article(
'https://www.example.com/some-article',
browser_user_agent=user_agent,
)
print(article.title)
# Using the Article class directly
article = Article(
'https://www.example.com/some-article',
browser_user_agent=user_agent,
)
article.download()
article.parse()
# Using newspaper.build for a whole news source
source = newspaper.build('https://www.example.com', browser_user_agent=user_agent)
Also, you can set the user-agent in the configuration object and pass it to the article or source: .. code-block:: python
from newspaper import Config, Article
config = Config() config.browser_user_agent = user_agent
article = Article(’https://www.example.com/some-article’, config=config) article.download() article.parse()
Rotating User-Agents with fake-useragent
When scraping many articles or sources, rotating the user-agent string on every request helps avoid rate-limiting and IP blocks. The fake-useragent library provides a simple way to generate realistic, random user-agent strings.
Install the necessary packages:
pip install newspaper4k fake-useragent
The example below creates a helper that picks a fresh random user-agent for each article download:
import newspaper
from newspaper import Article
from fake_useragent import UserAgent
ua = UserAgent()
def download_article(url: str) -> Article:
"""Download and parse a single article with a random user-agent."""
article = Article(url, browser_user_agent=ua.random)
article.download()
article.parse()
return article
urls = [
'https://www.bbc.com/news/world-us-canada-68084247',
'https://edition.cnn.com/2024/01/15/politics/biden-iowa/index.html',
'https://www.reuters.com/world/us/',
]
for url in urls:
art = download_article(url)
print(f"Title: {art.title}")
print(f"Authors: {art.authors}")
print(f"Agent: {art.config.browser_user_agent}")
print("-" * 60)
You can also rotate the user-agent when building a Source or when using
newspaper.mthreading.fetch_news:
import newspaper
from newspaper import Source
from newspaper.mthreading import fetch_news
from fake_useragent import UserAgent
ua = UserAgent()
# Give each source its own random user-agent
source_urls = ['https://slate.com', 'https://time.com', 'https://www.reuters.com']
sources = [
Source(url, browser_user_agent=ua.random) for url in source_urls
]
for source in sources:
source.build()
# Download all articles across all sources using multiple threads
fetch_news(sources, threads=4)
for source in sources:
for article in source.articles[:3]:
article.parse()
print(f"[{source.url}] {article.title}")