【问题标题】:Python nested loops only working on the first passPython 嵌套循环仅适用于第一遍
【发布时间】:2016-04-05 20:19:19
【问题描述】:

目标: 编写一个屏幕抓取工具来检查网页是否包含某些内容。

方法: 有两个配置文件,一个包含 URL 列表,另一个包含要搜索的字符串列表。打开这两个文件并将其内容作为两个数组读入。

循环遍历 URL 数组(我们称之为循环 A)。

对于每个 URL,使用 urllib 读取页面并通过在 \n 上拆分将其拆分为一个数组。循环遍历字符串列表(循环 B)。

对于字符串中的每一行,循环遍历 HTML 行(循环 C),并在每一行上进行模式匹配。如果找到匹配项,则将结果记录在输出文件中。

问题: 它正在打开配置文件。 循环 A 工作正常。循环 B 和 C 仅在循环 A 的第一次循环中工作。在循环 A 的第二次和第三次循环中,循环 B 没有发生。

请原谅我放了这么多调试代码。一个奇怪的怪癖是,我在代码第 52 行生成的输出中看到了一个神秘的“b”。

配置文件内容

urls.txt

http://uk.norton.com
http://us.norton.com
http://ie.norton.com

targetStrings.txt

Norton Online Backup
Norton Ultimate Help Desk

代码

# Import the modules we need
import urllib.request
import re

# Open the files we need
out = open('out.txt', 'w')
urls=open('urls.txt','r')
targetFile=open('targetStrings.txt','r',encoding=('utf-8'))

# function to take a URL, open the HTML, split it into an array, and return it
def getPage(url):
    return urllib.request.urlopen(url).read().decode().split('\n')

# function to kick out to an output file
def outFile(output):
    out.write(output + '\n')

# Function to test for matches    
def match(string, pageLine):
    if re.search(string.encode('utf-8'),pageLine):
        return True
    else:
        return False


#Loop through the URLs - Loop A
for url in urls:
    url=url.rstrip('\n')
    outFile('\nOpening ' + url) 
#    response=urllib.request.urlopen(url)
#    html=response.read().decode()
    html=getPage(str(url))
    if html !='':
        outFile('Page read successfully')
    else:
        outFile('Problem reading page')

    outFile(url + ' has ' + str(len(html)) + ' lines')

    #Loop through targetStrings - Loop B. This is only happening on the first pass of loop A.
    for line in targetFile:
        outFile('Beginning \'for line in targetFile:\' loop')
        line=line.rstrip('\n') #take out any \n newline characters at the end
        outFile('Looking for ' + line + ' in ' + url)
        foundCount=0

        # Loop through current HTML file - Loop C
        pageLineNumber=0
        for pageLine in html:
            pageLineNumber+=1
            pageLine=pageLine.encode('utf-8')
            outFile('Looking for ' + str(line) + ' in ' + str(pageLineNumber) + ' ' + str(pageLine))
            if match(line, pageLine):
                foundCount+=1
                outFile('FoundCount is ' + str(foundCount))
        outFile('Searched ' + str(pageLineNumber) + ' lines')

        if foundCount==0:
            outFile('Did not find ' + str(line))
        else:
            s=''
            if foundCount>0:
                s='s'
            outFile('Found ' + line + ' ' + str(foundCount) + ' time' + s)
            foundCount=0
f.close()
urls.close()
targetFile.close()

【问题讨论】:

    标签: python arrays loops


    【解决方案1】:

    问题不在于嵌套的 for 循环。在for line in targetFile: 中,您正在外循环的每次迭代中读取“targetFile”。您不能多次读取文件对象,因为一旦完全读取,读取指针设置为文件末尾。您要么需要创建一个新的文件对象,要么使用file_obj.seek(0) 将读取指针再次移动到文件的开头。 因此,您可以在for line in targetFile: 循环之后添加targetFile.seek(0) 作为外部循环的最后一行。

    for url in urls:
        # outer loop code
        for line in targetFile:
            # inner loop code
        targetFile.seek(0)
    
    f.close()
    urls.close()
    targetFile.close()
    

    @pvg 建议的其他更好的选择是读取列表中的所有行

    targetLines=open('targetStrings.txt','r',encoding=('utf-8')).readlines()
    

    然后使用该列表

    for line in targetLines:
    

    因为它会比一次又一次地读取文件更有效率。

    【讨论】:

    • 我喜欢(并赞成)这个,因为它包含一个“微创”解决方案。但是,即使开销(假设缓存)主要是系统调用,继续重新读取文件也是低效的。我认为您应该添加另一个明智的选择,即简单地将行读入列表,然后这将是一个很好的、全面的答案,并很好地解释了原始代码的问题。
    • 非常感谢!我以为我的代码已经将它读入了一个数组,但我不知道我需要做 readlines() 的事情。我正在学习 Python,所以这真的很有帮助。
    【解决方案2】:

    这里的问题是,当您第一次遍历文件 targetFile 时,其中的读取指针位于文件末尾,而当您再次尝试循环时,您将一无所获,因为您已经在结尾。你可以做2个思考来解决这个问题

    1. 在你迭代之前或之后将读取指针放在开始使用 seek 方法执行 targetFile.seek(0)
    2. 在变量中读取文件的整行并对其进行迭代。

    【讨论】:

      猜你喜欢
      • 2018-08-19
      • 2019-05-22
      • 2021-06-27
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      相关资源
      最近更新 更多