Current collected state Current
Observed since 20 Oct, 17:50 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A Python module to scrape PhD offers from academicpositions.com
A Python module to scrape PhD offers from academicpositions.com.
# Clone or navigate to the project directory
cd PhDFinder
# Install dependencies
pip install -e .
# Or install dependencies directly
pip install requests beautifulsoup4
from phd_scraper import AcademicPositionsScraper, PhDPosition
# Create scraper instance
scraper = AcademicPositionsScraper()
# Get PhD positions (basic usage)
positions = scraper.get_phd_positions(max_pages=2)
# Print results
for pos in positions:
print(f"{pos.title} at {pos.university}")
print(f" Location: {pos.location}")
print(f" Deadline: {pos.deadline}")
print(f" URL: {pos.url}")
print()
# Get Computer Science PhDs in Germany
positions = scraper.get_phd_positions(
max_pages=3,
country="germany",
field="computer-science"
)
# Get Physics PhDs in Switzerland
positions = scraper.get_phd_positions(
country="switzerland",
field="physics"
)
# Search for specific keywords
positions = scraper.search_positions(
keywords=["machine learning", "deep learning", "AI"],
country="germany",
max_pages=5
)
from phd_scraper.utils import export_to_json, export_to_csv, export_to_markdown
# Get positions
positions = scraper.get_phd_positions(max_pages=2)
# Export to different formats
export_to_json(positions, "phd_positions.json")
export_to_csv(positions, "phd_positions.csv")
export_to_markdown(positions, "phd_positions.md")
# Process positions one at a time (good for large datasets)
for position in scraper.iter_positions(country="sweden"):
print(position.summary())
# Process each position without loading all into memory
# Basic usage - get 2 pages of positions
python -m phd_scraper --pages 2
# Filter by country and field
python -m phd_scraper --country germany --field computer-science
# Export to JSON
python -m phd_scraper --output positions.json --format json --pages 3
# Export to CSV
python -m phd_scraper --output positions.csv --format csv
# Search with keywords
python -m phd_scraper --keywords "machine learning" "neural networks" --pages 5
# List available filters
python -m phd_scraper --list-filters
# Fast mode (skip detailed info)
python -m phd_scraper --no-details --pages 10
# Verbose output
python -m phd_scraper --verbose --pages 1
Each PhDPosition object contains:
| Field | Description |
|---|---|
title | Position title |
university | University/employer name |
location | Full location (city, country) |
country | Country name |
city | City name |
deadline | Application deadline |
published_date | When the position was published |
job_type | Type of position (PhD) |
fields | Research fields/disciplines |
description | Full job description |
requirements | Qualifications needed |
benefits | What the position offers |
url | Link to the job posting |
apply_url | Direct application link |
scraper = AcademicPositionsScraper(
request_delay=1.5, # Delay between requests (seconds)
timeout=30, # Request timeout (seconds)
max_retries=3, # Number of retry attempts
user_agent="Custom UA" # Custom user agent string
)
from phd_scraper.utils import (
filter_positions,
deduplicate_positions,
sort_positions
)
# Filter positions
filtered = filter_positions(
positions,
keywords=["AI", "robotics"],
countries=["germany", "switzerland"],
has_deadline=True
)
# Remove duplicates
unique = deduplicate_positions(positions)
# Sort by field
sorted_pos = sort_positions(positions, by="deadline")
[1] PhD Position in AI and Strategy
University: ETH Zürich
Location: Zurich, Switzerland
Deadline: Unspecified
Fields: Business Administration, Management, Artificial Intelligence
URL: https://academicpositions.com/ad/eth-zurich/2026/...
[2] Doctoral student in Radiofrequency ranging for Lunar orbits
University: KTH Royal Institute of Technology
Location: Stockholm, Sweden
Deadline: 2026-01-31 (Europe/Stockholm)
Fields: Physics, Space Science
URL: https://academicpositions.com/ad/kth-royal-institute-of-technology/2025/...
MIT License
pypistats · 54 observations shown. Missing days are unknown. Source category: overall: without mirrors.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-19 – 2026-10-19 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-18 – 2026-10-18 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-14 – 2026-10-14 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-13 – 2026-10-13 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-11 – 2026-10-11 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-10 – 2026-10-10 | 4 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-09 – 2026-10-09 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-08 – 2026-10-08 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-07 – 2026-10-07 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-06 – 2026-10-06 | 4 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-05 – 2026-10-05 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-04 – 2026-10-04 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-10-01 – 2026-10-01 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-30 – 2026-09-30 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-29 – 2026-09-29 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-27 – 2026-09-27 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-26 – 2026-09-26 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-24 – 2026-09-24 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-21 – 2026-09-21 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-20 – 2026-09-20 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-18 – 2026-09-18 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-16 – 2026-09-16 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-15 – 2026-09-15 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-12 – 2026-09-12 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-10 – 2026-09-10 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-09 – 2026-09-09 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-08 – 2026-09-08 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-07 – 2026-09-07 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-06 – 2026-09-06 | 5 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-05 – 2026-09-05 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-03 – 2026-09-03 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-09-01 – 2026-09-01 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-31 – 2026-08-31 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-28 – 2026-08-28 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-27 – 2026-08-27 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-24 – 2026-08-24 | 8 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-23 – 2026-08-23 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-20 – 2026-08-20 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-18 – 2026-08-18 | 18 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-17 – 2026-08-17 | 5 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-14 – 2026-08-14 | 4 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-13 – 2026-08-13 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-09 – 2026-08-09 | 3 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-06 – 2026-08-06 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-05 – 2026-08-05 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-04 – 2026-08-04 | 4 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-03 – 2026-08-03 | 4 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-02 – 2026-08-02 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-08-01 – 2026-08-01 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-07-30 – 2026-07-30 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-07-28 – 2026-07-28 | 6 | 2026-10-20T18:41:32.5560937Z |
| 2026-07-27 – 2026-07-27 | 2 | 2026-10-20T18:41:32.5560937Z |
| 2026-07-26 – 2026-07-26 | 1 | 2026-10-20T18:41:32.5560937Z |
| 2026-07-23 – 2026-07-23 | 5 | 2026-10-20T18:41:32.5560937Z |
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.0.0 | 14 Jan 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 17:50 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:1f5719486e04c768430111a2e30d7877ea15cf9614f893f31bc6f81517af4ac4