简体   繁体   中英

How to fix web scraping Python code “IndexError: list index out of range” when the code hits missing values

I am working on a web-scraping code. The code works well for the first page and then subsequent pages, however runs into problems when a different container comes up. The issue is that with most containers the class="date" contains two variables (the number of entries from the user [0] and the date [1]) however, when an anonymous user posts, it shows only the date [0]. Since the code is designed to look for the second entry it stops here due to an "IndexError: list index out of range"

I have tried creating an if loop, but since Im a beginner, it didn't work. Is there any way how to fix this ?

from bs4 import BeautifulSoup as soup
from urllib.request import urlopen as uReq
from random import randint
from time import sleep
from requests import get

out_filename = "Repromeda.csv"
headers = "text,user_name,date \n"
f = open(out_filename, "w")
f.write(headers)

pages = [str(i) for i in range(1,20)]

for page in pages:
    response = get('https://www.emimino.cz/diskuse/1ivf-repromeda-56566/strankovani/'+ page)
    sleep(randint(5,10))

    #opening up connection, grabing the page
    page_soup = soup(response.text, 'html.parser')
    #grabs each container
    containers = page_soup.findAll("div",{"class":"discussion_post"})

    for container in containers:
        text1 = container.div.p
        text = text1.text.replace('\n', ' ')

        user_container = container.div.b
        user_id = user_container.text

        date_container = container.findAll("span",{"class":"date"})
        date = date_container[1].text



        print("text: " + text + "\n" )
        print("user_id: " + user_id + "\n")
        print("date: " + date + "\n")
        # writes the dataset to file
        f.write(text.replace(",", "|") + ", " + user_id + ", " + date + "\n")

f.close()

Since the code is designed to look for the second entry it stops here due to an "IndexError: list index out of range" I have tried creating an if loop, but since Im a beginner, it didn't work.

Are you trying to capture date[1] only if it exists? In that case you can encapulsate your query in a simple try-catch block:

try:
    date = date_container[1].text
except IndexError:
    date = "Not Available"

Since the date is still available even if the user is anonymous, you can still capture the date with an except clause.

try:
    date = date_container[1].text
except IndexError:
    date = date_container[0].text

With bs4 4.7.1 + (don't know about earlier versions) you have access to :last-child pseudo selector. You can use this to ensure you always get the last element with class date within the container (without worrying about index)

for container in containers:
        text1 = container.div.p
        text = text1.text.replace('\n', ' ')

        user_container = container.div.b
        user_id = user_container.text

        date = container.select_one('.date:last-child').text

        print("text: " + text + "\n" )
        print("user_id: " + user_id + "\n")
        print("date: " + date)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM