ao3-api

repository·master·Indexed 43 days ago

https://github.com/wendytg/ao3_api

An 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.

Tokens
3.1K
Snippets
18
Records
21
Agent score
53%

What's inside ao3-api

  1. Overview of AO3 API

    master
    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.
  2. Refresh cached properties with Work.reload()

    master

    Most properties of an AO3.Work object (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 call work.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)
  3. Optimize work loading with threading and lazy loading

    master

    Loading works via the AO3.Work constructor is slow (~1-1.5s per work). To speed up bulk loading (e.g., from a Series), use these strategies:

    1. Lazy Initialization: Use load=False in the AO3.Work constructor to create the object without immediately making network requests.
    2. Parallel Loading: Use Work.reload(threaded=True) to return a Thread object that loads the work in the background. You can collect these threads and call .join() on them to wait for completion.
    3. Metadata Only: Use load_chapters=False in the constructor if you only need metadata and not chapter text.

    Note: Some methods like Series.work_list or Search.results return '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.")
  4. Update cached work properties

    master

    Most properties of a Work object (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 call work.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)
  5. Manage authenticated sessions

    master

    To 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 avoid AO3.utils.AuthError: Invalid authentication token.

    To use a session with a work object, pass it to the constructor: AO3.Work(workid, session=sess). Alternatively, use work.set_session(sess). For anonymous actions, use AO3.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)
  6. Load and inspect an AO3 Work

    master

    Use the AO3.Work class to load a work by its ID. You can extract the ID from a URL using AO3.utils.workid_from_url(url). Once loaded, you can access metadata like nchapters and iterate through chapters (which are AO3.Chapter objects) to access title and text.

    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 text
  7. Download extra resources

    master

    The AO3.extra module 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")
  8. Search for works using the Search class

    master

    The AO3.Search class provides an automated way to search for works. You can define constraints like any_field and word_count using AO3.utils.Constraint. After calling search.update(), you can access search.total_results and iterate over search.results to get Work objects. Use search.page = N to 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 = 2
  9. Download works as files

    master

    You can download a work in various formats including AZW3, EPUB, HTML, MOBI, and PDF using the work.download(format) method.

    import AO3
    
    work = AO3.Work(14392692)
    with open(f"{work.title}.pdf", "wb") as file:
        file.write(work.download("PDF"))