Scan your links.txt to identify unclaimed POAP links with a very simple Python script

gm, here is a simple script to scan which links of your links.txt file stills able to be claimed :link:

This is very useful when you can’t confirm if the people that were given a link/QR claimed it or not and you have limited POAPs so you would like to recycle them.

In example I’m giving POAPs to people that have eaten a special dish using a QR card, I want to avoid forwarding so I’m also using unique links for each claim, but anyway is possible that some of them will forget to claim it or loose the QR code card, so on the last week of my activation I will scan all the links with this script and reuse the ones that were not claimed but were given away.

At the end you will have 2 files that look like this:


For this example I just scanned 6 links, 5 unused and 1 claimed.

Some initial notes :nerd_face:

  • This tutorial is designed to be executed with python in the command line/shell of your own computer.
  • You must have python installed and ready to run in your command line/shell.
  • The script use the web browser so you will be able to see the proccess happening automatically in your screen, or not if you configure it to run in the background.
  • If you get a message that some library is missing, please come and ask here or use GPT / Google!

:white_check_mark: If you follow the steps, you don’t need to know anything about coding to run this successfully… but never run code that you can’t understand in your computer! :warning:

Get a “claimable-links.txt” and “used-links.txt” lists scanning your POAP links.txt file

To use it:

  1. Create the “check-links.py” file in the same directory/filder your links.txt is.
  2. Install the required libraries on your local machine, execute: “pip install selenium”
  3. To run the script execute: “check-links.py” and after the sacanning both files would be generated.
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, TimeoutException
import time

# Configurations
DELAY = 10  # Time (in seconds) to wait for each link to fully load.
BROWSER = 'Firefox'  # Choose between 'Firefox', 'Chrome', 'Brave', 'Edge', or 'Safari'.
VISIBLE_MODE = True  # Set to True to see the browser in action. False will execute it in the background.
TIMEOUT = 15  # Maximum time (in seconds) to wait for a link to load.

def check_link_status(driver, link, delay):
    try:
        driver.get(link)
    except TimeoutException:
        return "Unknown"  # Link was not loaded in the waiting time.

    time.sleep(delay)
    try:
        driver.find_element(By.XPATH, "//*[contains(text(), 'Congratulations!')]")
        return "Used"
    except NoSuchElementException:
        pass

    try:
        driver.find_element(By.XPATH, "//form[contains(@class, 'claim-form')]")
        return "Not Used"
    except NoSuchElementException:
        pass

    return "Unknown"

def initialize_browser():
    if BROWSER == 'Firefox':
        options = webdriver.FirefoxOptions()
        if not VISIBLE_MODE:
            options.add_argument('-headless')
        driver = webdriver.Firefox(options=options)
        driver.set_page_load_timeout(TIMEOUT)
        return driver
    elif BROWSER == 'Chrome':
        options = webdriver.ChromeOptions()
        options.headless = not VISIBLE_MODE
        return webdriver.Chrome(options=options)
    elif BROWSER == 'Brave':
        options = webdriver.ChromeOptions()
        options.binary_location = 'path_to_brave_browser'  # Add the path to Brave Browser
        options.headless = not VISIBLE_MODE
        return webdriver.Chrome(chrome_options=options)
    elif BROWSER == 'Edge':
        options = webdriver.EdgeOptions()
        options.use_chromium = True
        options.headless = not VISIBLE_MODE
        return webdriver.Edge(options=options)
    elif BROWSER == 'Safari':
        # Safari can't be used in background mode natively.
        return webdriver.Safari()

def main():
    driver = initialize_browser()

    used_links = []
    not_used_links = []
    unknown_links = []

    with open('links.txt', 'r') as file:
        links = [line.strip() for line in file]

    start_time = time.strftime('%Y-%m-%d %H:%M:%S')
    for link in links:
        status = check_link_status(driver, link, DELAY)
        if status == "Used":
            used_links.append(link)
        elif status == "Not Used":
            not_used_links.append(link)
        else:
            unknown_links.append(link)
    end_time = time.strftime('%Y-%m-%d %H:%M:%S')

    driver.quit()

    with open('used-links.txt', 'w') as f:
        f.write(f"Checked on: {start_time} to {end_time}\n")
        for link in used_links:
            f.write(link + '\n')

    with open('claimable-links.txt', 'w') as f:
        f.write(f"Checked on: {start_time} to {end_time}\n")
        for link in not_used_links:
            f.write(link + '\n')

if __name__ == "__main__":
    main()

There is a few important configurations that are listed below:

  • DELAY = 10 # Time (in seconds) to wait for each link to fully load.
  • BROWSER = ‘Firefox’ # Choose between ‘Firefox’, ‘Chrome’, ‘Brave’, ‘Edge’, or ‘Safari’.
  • VISIBLE_MODE = True # Set to True to see the browser in action. False will execute it in the background.
  • TIMEOUT = 15 # Maximum time (in seconds) to wait for a link to load.
  • options.binary_location = ‘path_to_brave_browser’ # Add the path to Brave Browser there if is your choice.
  • Ensure that the respective web driver (geckodriver for Firefox, chromedriver for Chrome, etc.) is installed and available in the system PATH. This can happen automatically after first attemp to run the script, so you will need to run it twice.

Considerations:

  • You might be blocked somehow by the POAP website if you abuse on this functionallities, use just for the good faith use, to check your links.
  • There is a time delay of 10 seconds for each link, at least 5 seconds are needed by my experience.
  • If you are going to check more than 50 links consider running this in batches, splitting your links.txt file into different files and run them spaced in time.

Enjoy distributing your POAPs responsibly and take measures to maximize the utility of the precious links you have!

My X/Twitter: https://x.com/ariutokintumi

Feel free to ask any question :point_down:

For some reason I can’t update the original post. If some mod can edit it I will appreciate.

This “check-links.py” script is updated due to beautiful a POAP UI update with new functionalities integration. The new script just vary on the string detection in the used/unused respective HTML code to find in the POAP page:

    try:
        driver.find_element(By.XPATH, "//*[contains(text(), 'WOO HOO!')]")
        return "Used"
    except NoSuchElementException:
        pass

    try:
        driver.find_element(By.XPATH, "//form[contains(@class, 'MintForm_form__NE__8')]")
        return "Not Used"
    except NoSuchElementException:
        pass

So, the complete new “check-links.py” script is the follow one:

from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, TimeoutException
import time

# Configuraciones
DELAY = 10  # Tiempo de espera en segundos para cada enlace.
BROWSER = 'Firefox'  # Elije entre 'Firefox', 'Chrome', 'Brave', 'Edge', o 'Safari'.
VISIBLE_MODE = True  # True para ver el navegador mientras se ejecuta, False para modo silencioso.
TIMEOUT = 15  # Tiempo máximo para cargar una página.

def check_link_status(driver, link, delay):
    try:
        driver.get(link)
    except TimeoutException:
        return "Unknown"  # No pudimos cargar la página en el tiempo esperado.

    time.sleep(delay)
    try:
        driver.find_element(By.XPATH, "//*[contains(text(), 'WOO HOO!')]")
        return "Used"
    except NoSuchElementException:
        pass

    try:
        driver.find_element(By.XPATH, "//form[contains(@class, 'MintForm_form__NE__8')]")
        return "Not Used"
    except NoSuchElementException:
        pass

    return "Unknown"

def initialize_browser():
    if BROWSER == 'Firefox':
        options = webdriver.FirefoxOptions()
        if not VISIBLE_MODE:
            options.add_argument('-headless')
        driver = webdriver.Firefox(options=options)
        driver.set_page_load_timeout(TIMEOUT)
        return driver
    elif BROWSER == 'Chrome':
        options = webdriver.ChromeOptions()
        options.headless = not VISIBLE_MODE
        return webdriver.Chrome(options=options)
    elif BROWSER == 'Brave':
        options = webdriver.ChromeOptions()
        options.binary_location = 'path_to_brave_browser'  # Añade el path al ejecutable de Brave.
        options.headless = not VISIBLE_MODE
        return webdriver.Chrome(chrome_options=options)
    elif BROWSER == 'Edge':
        options = webdriver.EdgeOptions()
        options.use_chromium = True
        options.headless = not VISIBLE_MODE
        return webdriver.Edge(options=options)
    elif BROWSER == 'Safari':
        # Safari no soporta modo silencioso directamente.
        return webdriver.Safari()

def main():
    driver = initialize_browser()

    used_links = []
    not_used_links = []
    unknown_links = []

    with open('links.txt', 'r') as file:
        links = [line.strip() for line in file]

    start_time = time.strftime('%Y-%m-%d %H:%M:%S')
    for link in links:
        status = check_link_status(driver, link, DELAY)
        if status == "Used":
            used_links.append(link)
        elif status == "Not Used":
            not_used_links.append(link)
        else:
            unknown_links.append(link)
    end_time = time.strftime('%Y-%m-%d %H:%M:%S')

    driver.quit()

    with open('used-links.txt', 'w') as f:
        f.write(f"Checked on: {start_time} to {end_time}\n")
        for link in used_links:
            f.write(link + '\n')

    with open('claimable-links.txt', 'w') as f:
        f.write(f"Checked on: {start_time} to {end_time}\n")
        for link in not_used_links:
            f.write(link + '\n')

if __name__ == "__main__":
    main()

Enjoy distributing your POAPs responsibly and take measures to maximize the utility of the precious links you have!

Feel free to ask any question :point_down:

3 Likes