ao3-api
repository·master·Indexed 43 days ago
https://github.com/wendytg/ao3_apiAn unofficial Python API for accessing data from Archive of Our Own (AO3), including works, users, searches, and comments. Version 2.3.1 allows for programmatic access to metadata, chapter text, and user profiles, as well as downloading works in formats such as EPUB, PDF, and MOBI. It includes support for authenticated sessions to manage kudos and comments, and provides tools for bulk loading works via threading and lazy initialization.
What's inside ao3-api
- AO3 API is an unofficial Python library designed to access data from Archive of Our Own (archiveofourown.org). It achieves this through webscraping and other specialized tools to provide programmatic access to AO3 data.
Refresh cached properties with Work.reload()
masterMost properties of an
AO3.Workobject (e.g.,kudos,bookmarks, author names) are cached properties. Once accessed, the value is stored and will not update even if the actual value on AO3 changes. To sync the object with the current state on the server, you must callwork.reload().import AO3 # Assuming work is already instantiated print(work.kudos) work.leave_kudos() work.reload() # Required to see the updated count print(work.kudos)Optimize work loading with threading and lazy loading
masterLoading works via the
AO3.Workconstructor is slow (~1-1.5s per work). To speed up bulk loading (e.g., from aSeries), use these strategies:- Lazy Initialization: Use
load=Falsein theAO3.Workconstructor to create the object without immediately making network requests. - Parallel Loading: Use
Work.reload(threaded=True)to return aThreadobject that loads the work in the background. You can collect these threads and call.join()on them to wait for completion. - Metadata Only: Use
load_chapters=Falsein the constructor if you only need metadata and not chapter text.
Note: Some methods like
Series.work_listorSearch.resultsreturn 'semi-loaded' objects where metadata is cached but chapter text is not yet available.import AO3 import time series = AO3.Series(1295090) works = [] threads = [] start = time.time() # Fast parallel loading pattern for work in series.work_list: works.append(work) threads.append(work.reload(threaded=True)) for thread in threads: thread.join() print(f"Loaded {len(works)} works in {round(time.time()-start, 1)} seconds.")- Lazy Initialization: Use
Update cached work properties
masterMost properties of a
Workobject (e.g.,kudos,bookmarks, author names) are cached properties. Once accessed, the value is stored and will not update even if the data changes on AO3. To refresh these values, you must callwork.reload().import AO3 sess = AO3.GuestSession() work = AO3.Work(16721367, sess) print(work.kudos) work.leave_kudos() work.reload() # Refresh the cache print(work.kudos)Manage authenticated sessions
masterTo perform actions like leaving kudos, commenting, or viewing bookmarks, use
AO3.Session(username, password).Important: You must call
session.refresh_auth_token()for activities like leaving kudos or comments to avoidAO3.utils.AuthError: Invalid authentication token.To use a session with a work object, pass it to the constructor:
AO3.Work(workid, session=sess). Alternatively, usework.set_session(sess). For anonymous actions, useAO3.GuestSession().import AO3 session = AO3.Session("username", "password") print(f"Bookmarks: {session.bookmarks}") # Refresh token before performing authenticated actions session.refresh_auth_token() # Use session with a work object work = AO3.Work(18001499, session=session) session.kudos(work)Load and inspect an AO3 Work
masterUse the
AO3.Workclass to load a work by its ID. You can extract the ID from a URL usingAO3.utils.workid_from_url(url). Once loaded, you can access metadata likenchaptersand iterate throughchapters(which areAO3.Chapterobjects) to accesstitleandtext.import AO3 url = "https://archiveofourown.org/works/14392692/chapters/33236241" workid = AO3.utils.workid_from_url(url) work = AO3.Work(workid) print(f"Chapters: {work.nchapters}") print(work.chapters[1].title) # Second chapter name print(work.chapters[1].text) # Second chapter textInstall the ao3_api package
masterInstall the AO3 API using pip to access Archive of Our Own data via Python.
pip install ao3_apiInstall ao3_api via pip
masterYou can install the
ao3_apipackage directly from PyPI using pip.pip install ao3_apiInstall ao3_api from source
masterAlternatively, you can install the package by cloning the repository and building it from the source files.Download extra resources
masterThe
AO3.extramodule provides access to non-core resources (e.g., lists of fandoms).AO3.extra.get_resources(): List available resources.AO3.extra.download(resource_name): Download a specific resource.AO3.extra.download_all(): Download all available resources.
import AO3 # List available resources print(AO3.extra.get_resources()) # Download a specific resource AO3.extra.download("fandoms")Search for works using the Search class
masterThe
AO3.Searchclass provides an automated way to search for works. You can define constraints likeany_fieldandword_countusingAO3.utils.Constraint. After callingsearch.update(), you can accesssearch.total_resultsand iterate oversearch.resultsto getWorkobjects. Usesearch.page = Nto navigate through result pages.import AO3 search = AO3.Search(any_field="Clarke Lexa", word_count=AO3.utils.Constraint(5000, 15000)) search.update() print(search.total_results) for result in search.results: print(result) # To get the next page search.page = 2Download works as files
masterYou can download a work in various formats including
AZW3,EPUB,HTML,MOBI, andPDFusing thework.download(format)method.import AO3 work = AO3.Work(14392692) with open(f"{work.title}.pdf", "wb") as file: file.write(work.download("PDF"))