Of course! Python Challenge 3 is a classic that tests your ability to work with strings and regular expressions.
The Challenge
URL: http://www.pythonchallenge.com/pc/def/linkedlist.php
Hint: The page title is "nothing" and the image shows a picture of a zipper. The page itself says:
urllib cannot join relative urlbut... maybe notand the next nothing is 12345
Goal
Find the next "nothing" in a sequence until you reach the final URL.
Step-by-Step Solution
Step 1: Understanding the Initial State
The starting point is a URL that takes you to a page. The first clue is that the "next nothing" is 12345. This suggests we need to construct a new URL to get the next clue.
The pattern seems to be:
http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=12345
Step 2: The First Attempt (and the problem)
Let's try to follow the instructions. We'll use Python's requests library to get the content of the URL.
import requests
# The starting "nothing" value
nothing = "12345"
# Construct the URL
url = f"http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={nothing}"
# Get the page content
response = requests.get(url)
print(response.text)
Output:
and the next nothing is 44827
Okay, it worked! The first clue gave us the second one. Let's try to do this programmatically.
Step 3: Building the Loop
We can put this logic in a loop. We'll start with 12345, get the next value, and use that value in the next request.
import requests
nothing = "12345"
for _ in range(10): # Let's do a few iterations to see the pattern
url = f"http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={nothing}"
response = requests.get(url)
print(f"Current nothing: {nothing}, Response: {response.text.strip()}")
# Extract the next "nothing" from the response text
# The text is like "and the next nothing is 44827"
# We can split by space and take the last part.
next_nothing = response.text.split()[-1]
nothing = next_nothing
Output:
Current nothing: 12345, Response: and the next nothing is 44827
Current nothing: 44827, Response: and the next nothing is 45439
Current nothing: 45439, Response: and the next nothing is 94191
...and so on
This seems to be working. We can just keep running this loop until we get a different kind of response.
Step 4: The Catch - Dividing by Two
If you run the loop for a while, you'll eventually get this response:
and the next nothing is 16044/2
Our simple split()[-1] logic will now fail because it tries to convert "16044/2" to an integer.
We need to handle this. The hint in the URL (urllib cannot join relative url) and the response itself suggest we should perform the division.
Let's update our code:
import requests
nothing = "12345"
while True:
url = f"http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={nothing}"
response = requests.get(url)
print(response.text)
# Check if the response indicates we should divide
if "divisible by 2" in response.text:
nothing = str(int(nothing) // 2)
print(f"Dividing by 2. New nothing: {nothing}")
else:
# Extract the next "nothing" from the response text
next_nothing = response.text.split()[-1]
nothing = next_nothing
# A safety break in case of an infinite loop
if nothing == "peak.html":
break
Step 5: The Final Solution
Running the code from Step 4 will eventually lead you to a page that says:
Yes. Divide by two and keep going.
This confirms our logic. If you continue running the loop, you will eventually get a response that is not a number. The final response you'll get is:
peak.html
This is the answer! The URL for the next level is no longer linkedlist.php but peak.html.
The Complete Code
Here is the complete, robust script that solves the challenge.
import requests
def solve_challenge_3():
"""
Solves Python Challenge 3 by following the chain of 'nothing' values.
"""
# Start with the initial "nothing" value from the page
nothing = "12345"
base_url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="
print("Starting the chain...")
while True:
# Construct the full URL for the current 'nothing'
url = f"{base_url}{nothing}"
try:
# Fetch the content of the page
response = requests.get(url)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
text = response.text.strip()
print(f"Fetching: {url}")
print(f"Response: {text}")
# Check if we've reached the end of the chain
if text == "peak.html":
print("\n--- Challenge Complete ---")
print(f"The final URL is: http://www.pythonchallenge.com/pc/def/{text}")
break
# Check if the response asks us to divide the current 'nothing'
if "divisible by 2" in text:
nothing = str(int(nothing) // 2)
print(f"-> Instruction: Divide by 2. New nothing is: {nothing}\n")
else:
# Otherwise, extract the next 'nothing' from the response text
# e.g., "and the next nothing is 94191"
next_nothing = text.split()[-1]
nothing = next_nothing
print(f"-> Next nothing is: {nothing}\n")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
break
# Run the solver
if __name__ == "__main__":
solve_challenge_3()
Key Concepts Learned
- Web Scraping with
requests: How to programmatically fetch content from a URL. - String Manipulation: Using
split()and indexing ([-1]) to extract specific parts of a string. - Conditional Logic: Using
if/elsestatements to handle different types of responses from the server. - Loops: Using a
while Trueloop to repeatedly perform an action until a termination condition is met. - Error Handling: Using
try...exceptto make the script more robust against network errors. - Problem Solving: The core of the challenge is not just coding, but reading the clues carefully and adapting your logic when the rules change (the division part).
Next Level
Once you have the answer peak.html, the URL for the next challenge is:
http://www.pythonchallenge.com/pc/def/peak.html
