【问题标题】:Python loop skipping one element while loopingPython循环在循环时跳过一个元素
【发布时间】:2018-02-04 01:30:48
【问题描述】:

我有这段代码在Top Alexa 1000 网站上循环,并获得允许Sign UpLogin 以任何形式出现的代码。如果在此循环的其中一个迭代中有一个网站卡住或以任何形式抛出Exception,我将其从列表中删除,并使用下一个元素重新开始循环。我正在使用Python 中的selenium 包来执行此操作。它工作正常,除了由于某种原因它循环遍历我的 alexa_1000 包含列表的变量中的所有其他元素(即跳过一个元素),而不是遍历每个元素。有人可以帮忙吗?我看到的代码似乎没有什么问题,我一直在调试它以查看程序流程,但真的无法弄清楚发生了什么。该程序的一般流程似乎很好。当我打印每个循环的索引时,要查看跳过的性质,从 0 到 1 到 2 到 3 的意义上来说,这似乎也很好。很高兴有任何帮助。代码如下:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException


def get_alexa_top_pages():

    sites = []

    with open('topsites_1000.txt', 'r') as f:

        for line in f:
            line = line.strip('\n')
            sites.append(line)

    sites = filter(None, sites)


    sites = ['http://www.' + site for site in sites]

    return sites

def main():

    alexa_1000 = get_alexa_top_pages()
    out = open('sites_with_login.txt', 'w')
    sign_in_strings = ['sign in', 'signin', 'login', 'log in', 'sign up', 'signup']

    driver = webdriver.Firefox()
    driver.set_page_load_timeout(30)

    for index, page in enumerate(alexa_1000):


        try:

            print "Loading page %s (num %d)" %(page, index + 1)
            driver.get(page)
            html_source = driver.page_source
            html_source = html_source.lower()
            present = any([i in html_source for i in sign_in_strings])
            if present:
                out.write(page + '\n')

            alexa_1000.remove(page)

        except TimeoutException as ex:
            alexa_1000.remove(page)
            continue
        except Exception as ex:
            alexa_1000.remove(page)
            continue    


    out.close()

if __name__ == "__main__":
    main()

【问题讨论】:

  • 在枚举集合时移除元素会干扰枚举。
  • @Jerry101 我后来才添加 enumerate 来测试它,否则通常的 for page in alexa_1000 具有相同的效果。
  • 是的,我的意思是在循环值的意义上“枚举”。之所以会出现这个常见问题是因为循环记得接下来提供nth 项,并且删除较早的项会使项向下移动,因此位于collection[n] 的项移动到collection[n-1]。一种解决方法是向后循环集合:for page in alexa_1000[::-1]:,因此将后面的项目向下移动不会干扰。另一种解决方法是制作一个临时副本,如 The for statement 中所述。
  • @Jerry101 非常感谢您的解释! :) 学到了很棒的东西。

标签: python loops selenium


【解决方案1】:

有不同的方法可以解决这个问题。问题是因为您在枚举时触摸了枚举。应该始终避免这种情况。你可以通过重写你的代码来做到这一点

使用集合代替数组

from selenium import webdriver
from selenium.common.exceptions import TimeoutException


def get_alexa_top_pages():

    sites = []

    with open('topsites_1000.txt', 'r') as f:

        for line in f:
            line = line.strip('\n')
            sites.append(line)

    sites = filter(None, sites)


    sites = ['http://www.' + site for site in sites]

    return sites

def main():

    alexa_1000 = set(get_alexa_top_pages())

    alexa_invalid = set()

    out = open('sites_with_login.txt', 'w')
    sign_in_strings = ['sign in', 'signin', 'login', 'log in', 'sign up', 'signup']

    driver = webdriver.Firefox()
    driver.set_page_load_timeout(30)

    for index, page in enumerate(alexa_1000):


        try:

            print "Loading page %s (num %d)" %(page, index + 1)
            driver.get(page)
            html_source = driver.page_source
            html_source = html_source.lower()
            present = any([i in html_source for i in sign_in_strings])
            if present:
                out.write(page + '\n')

        except TimeoutException as ex:
            alexa_invalid.add(page)
            continue
        except Exception as ex:
            alexa_invalid.add(page)
            continue    

    alexa_valid = alexa_1000 - alexa_invalid

    out.close()

if __name__ == "__main__":
    main()

在此您使用 set,一个用于循环,一个用于维护无效列表。如果发生异常,则更新无效的。最后,您也可以将两者相减以找到有效站点

使用反向数组并弹出

from selenium import webdriver
from selenium.common.exceptions import TimeoutException


def get_alexa_top_pages():

    sites = []

    with open('topsites_1000.txt', 'r') as f:

        for line in f:
            line = line.strip('\n')
            sites.append(line)

    sites = filter(None, sites)


    sites = ['http://www.' + site for site in sites]

    return sites

def main():

    alexa_1000 = get_alexa_top_pages()

    out = open('sites_with_login.txt', 'w')
    sign_in_strings = ['sign in', 'signin', 'login', 'log in', 'sign up', 'signup']

    driver = webdriver.Firefox()
    driver.set_page_load_timeout(30)

    for index, page in enumerate(alexa_1000[::-1]):


        try:

            print "Loading page %s (num %d)" %(page, index + 1)
            driver.get(page)
            html_source = driver.page_source
            html_source = html_source.lower()
            present = any([i in html_source for i in sign_in_strings])
            if present:
                out.write(page + '\n')

        except TimeoutException as ex:
            alexa_1000.pop()
            continue
        except Exception as ex:
            alexa_1000.pop()
            continue    

    out.close()

if __name__ == "__main__":
    main()

在这种情况下,您以相反的顺序循环,而那些出错的,您只需将它们弹出即可。最后alexa_1000 将拥有您处理的所有有效网站

有很多方法可以解决这个问题,上面只展示了其中两种你可以理想使用的方法

【讨论】:

  • 非常感谢您的回答!我很感激。反向数组弹出示例非常酷。
猜你喜欢
  • 2022-01-21
  • 2012-03-02
  • 1970-01-01
  • 2019-01-01
  • 2015-07-17
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 2014-01-08
相关资源
最近更新 更多