0

我收到此错误:

Traceback (most recent call last):
  File "script.py", line 7, in <module>
    proxy = urllib2.ProxyHandler(line)
  File "/usr/lib/python2.7/urllib2.py", line 713, in __init__
    assert hasattr(proxies, 'has_key'), "proxies must be a mapping"
AssertionError: proxies must be a mapping

当我运行以下脚本时:

import urllib2  
u=open('urls.txt')
p=open('proxies.txt')
for line in p:
    proxy = urllib2.ProxyHandler(line)
    opener = urllib2.build_opener(proxy)
    urllib2.install_opener(opener)
    for url in u:
        urllib.urlopen(url).read()

u.close()
p.close()

我的 urls.txt 文件有这个:

'www.google.com'
'www.facebook.com'
'www.reddit.com'

我的 proxies.txt 有这个:

{'https': 'https://94.142.27.4:3128'}
{'http': 'http://118.97.95.174:8080'}
{'http':'http://66.62.236.15:8080'}

我在hidemyass.com找到了它们

从我所做的谷歌搜索来看,大多数遇到此问题的人的代理格式错误。这是这里的情况吗?

4

1 回答 1

2

正如文档所说:

如果给出了代理,它必须是一个将协议名称映射到代理 URL 的字典。

但是在您的代码中,它只是一个字符串。proxies.txt特别是,它是您文件中的一行:

p=open('proxies.txt')
for line in p:
    proxy = urllib2.ProxyHandler(line)

查看该文件,看起来这些行旨在类似于reprPython 字典。而且,鉴于所有键和值都是字符串文字,这意味着您可以使用ast.literal_eval它来恢复原始字典:

p=open('proxies.txt')
for line in p:
    d = ast.literal_eval(line)
    proxy = urllib2.ProxyHandler(d)

当然,这不适用于您的示例数据,因为其中一行缺少'字符。但如果你解决了这个问题,它会……</p>

但是,使用实际用于数据交换的格式可能会更好。例如,JSON 和你所拥有的一样是人类可读的,并且没有什么不同:

{"https": "https://94.142.27.4:3128"}
{"http": "http://118.97.95.174:8080"}
{"http": "http://66.62.236.15:8080"}

使用 JSON 的优点是有很多工具可以验证、编辑等 JSON,而没有用于自定义格式的工具;什么是有效的和无效的规则是显而易见的,而不是你必须猜测的东西;并且无效数据的错误消息可能会更有帮助(例如“在第 1 行第 10 列(字符 10)期望属性名称”而不是“解析时意外的 EOF”)。


请注意,一旦您解决了这个问题,您将遇到另一个带有 URL 的问题。毕竟,'www.google.com'\n不是你想要的,它是www.google.com。所以你将不得不去掉换行符和引号。同样,你可以ast.literal_eval在这里使用。或者您可以使用 JSON 作为交换格式。

但实际上,如果您只是想每行存储一个字符串,为什么不按原样存储字符串,而不是尝试存储这些字符串的字符串表示形式(加上额外的引号)?


除此之外还有更多的问题。

即使你去掉了多余的引号,www.google.com它也不是 URL,它只是一个主机名。http://www.google.com是你想要的。除非你想要https://www.google.com,或者其他一些方案。

您正在尝试'urls.txt'为每个代理循环一次。这将处理仅安装了第一个代理的所有 URL,然后处理安装了前两个代理的其余部分(这没什么,因为您已经完成了所有这些),然后安装了其余部分(仍然什么都没有)三装。将循环移到url循环之外proxy

最后,这些并不是真正的问题,但是当我们这样做时……使用with语句可以比使用手动调用更容易编写更健壮的代码close,并且它使您的代码更短且更易于启动。此外,通常最好等到需要文件后再尝试打开它。从长远来看,变量名和变量名u只会p造成更多的混乱,而不是在短期内节省打字。

哦,只是调用urllib.urlopen(url).read()而不做任何结果除了浪费几秒钟和一点网络带宽之外不会产生任何影响,但我假设你已经知道了,为了简单起见省略了细节.

将它们放在一起,并假设您如上所述修复了两个文件:

import json
import urllib2  

with open('proxies.txt') as proxies:
    for line in proxies:
        proxy = json.loads(line)
        proxy_handler = urllib2.ProxyHandler(proxy)
        opener = urllib2.build_opener(proxy_handler)
        urllib2.install_opener(opener)
with open('urls.txt') as urls:
    for line in urls:
        url = line.rstrip()
        data = urllib.urlopen(url).read()
        # do something with data

事实证明,您希望通过每个代理尝试所有 URL,而不是通过所有代理尝试所有 URL,或者通过第一个然后是前两个,依此类推。

您可以通过缩进 secondwithforfirst来做到这一点for。但是一次阅读它们可能更简单(并且可能更有效,尽管我怀疑这很重要):

with open('urls.txt') as f:
    urls = [line.rstrip() for line in f]
with open('proxies.txt') as proxies:
    for line in proxies:
        proxy = json.loads(line)
        proxy_handler = urllib2.ProxyHandler(proxy)
        opener = urllib2.build_opener(proxy_handler)
        urllib2.install_opener(opener)
        for url in urls:
            data = urllib.urlopen(url).read()
            # do something with data

当然,这意味着在进行任何工作之前阅读整个 URL 列表。我怀疑这很重要,但如果确实如此,你可以使用这个tee技巧来避免它。

于 2013-08-15T22:30:12.463 回答