如何使用python根据条件从列表中弹出项目并将其推回到列表中

2024-10-04 05:24:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我有用于爬网的URL列表。['http://domain1.com','http://domain1.com/page1','http://domain2.com']

代码:

prev_domain = ''
while urls:
    url = urls.pop()
    if base_url(url) == prev_domain: # base_url is custom function return domain of an url
        urls.append(url) # is this is possible?
        continue 
    else:
        crawl(url)

基本上我不想爬同一个领域的网页不断。继续爬网一个域url,返回http响应状态码429:请求太多。用户在给定的时间内发送了太多请求(“速率限制”)。为了回避这个问题,我打算用下面的逻辑。你知道吗

循环遍历列表中的所有项,并将当前元素基url与以前处理的元素基url进行比较。你知道吗

如果基本URL不同,则处理下一步,否则不处理当前元素,只需将此元素附加到同一列表中。你知道吗

注意:如果列表中的URL属于同一域,请延迟处理每个元素,然后执行。你知道吗

请提供您的想法。你知道吗


Tags: 代码comhttpurl元素列表baseis
2条回答

检查以下代码段

urls = ['http://domain1.com','http://domain1.com/page1','http://domain2.com']

crawl_for_urls = {}
for url in urls:
    domain = base_url(url)
    if domain not in crowl_for_urls:
        crawl_for_urls.update({domain:url})
        crawl(url)

crawl()将仅为唯一域调用。你知道吗

或者您可以使用:

urls = ['http://domain1.com','http://domain1.com/page1','http://domain2.com']

crawl_for_urls = {}
for url in urls:
    domain = base_url(url)
    if domain not in crowl_for_urls:
        crawl_for_urls.update({domain:[url]})
        crawl(url)
    else:
        crawl_for_urls.get(domain, []).append(url)

通过这种方式,您可以根据域对URL进行分类,也可以使用crawl()作为唯一域。你知道吗

您的算法几乎是正确的,但不是实现:

>>> L = [1,2,3]
>>> L.pop()
3
>>> L.append(3)
>>> L
[1, 2, 3]

这就是为什么你的程序会永远循环:如果这个域和前一个域是一样的,你只需要追加,然后弹出,然后追加,然后。。。。你需要的不是一堆,而是一个循环:

>>> L.pop()
3
>>> L.insert(0, 3)
>>> L
[3, 1, 2]

让我们看一下“abcd”排列的无序列表:

>>> L = [('b', 'c', 'd', 'a'), ('d', 'c', 'b', 'a'), ('a', 'c', 'd', 'b'), ('c', 'd', 'a', 'b'), ('b', 'd', 'a', 'c'), ('b', 'a', 'd', 'c'), ('b', 'c', 'a', 'd'), ('a', 'b', 'd', 'c'), ('d', 'a', 'b', 'c'), ('a', 'b', 'c', 'd'), ('d', 'c', 'a', 'b'), ('a', 'd', 'c', 'b'), ('d', 'a', 'c', 'b'), ('c', 'd', 'b', 'a'), ('d', 'b', 'c', 'a'), ('d', 'b', 'a', 'c'), ('a', 'd', 'b', 'c'), ('b', 'd', 'c', 'a'), ('c', 'b', 'd', 'a'), ('c', 'a', 'b', 'd'), ('b', 'a', 'c', 'd')]

第一个字母是domain。下面是对您的代码稍加修改的版本:

>>> prev = None
>>> while L:
...     e = L.pop()
...     if L and e[0] == prev:
...         L.insert(0, e)
...     else:
...         print(e)
...         prev = e[0]
('b', 'a', 'c', 'd')
('c', 'a', 'b', 'd')
('b', 'd', 'c', 'a')
('a', 'd', 'b', 'c')
('d', 'b', 'a', 'c')
('c', 'd', 'b', 'a')
('d', 'a', 'c', 'b')
('a', 'd', 'c', 'b')
('d', 'c', 'a', 'b')
('a', 'b', 'c', 'd')
('d', 'a', 'b', 'c')
('a', 'b', 'd', 'c')
('b', 'c', 'a', 'd')
('c', 'd', 'a', 'b')
('a', 'c', 'd', 'b')
('d', 'c', 'b', 'a')
('b', 'c', 'd', 'a')
('c', 'b', 'd', 'a')
('d', 'b', 'c', 'a')
('b', 'a', 'd', 'c')
('b', 'd', 'a', 'c')

修改是:if L and,因为如果列表域的最后一个元素是prev,那么您将永远使用单元素列表循环:pop,与prev、insert、pop相同,…(与pop/append相同)

下面是另一个选项:创建dict domain -> list of urls

>>> d = {}
>>> for e in L:
...     d.setdefault(e[0], []).append(e)
>>> d
{'b': [('b', 'c', 'd', 'a'), ('b', 'd', 'a', 'c'), ('b', 'a', 'd', 'c'), ('b', 'c', 'a', 'd'), ('b', 'd', 'c', 'a'), ('b', 'a', 'c', 'd')], 'd': [('d', 'c', 'b', 'a'), ('d', 'a', 'b', 'c'), ('d', 'c', 'a', 'b'), ('d', 'a', 'c', 'b'), ('d', 'b', 'c', 'a'), ('d', 'b', 'a', 'c')], 'a': [('a', 'c', 'd', 'b'), ('a', 'b', 'd', 'c'), ('a', 'b', 'c', 'd'), ('a', 'd', 'c', 'b'), ('a', 'd', 'b', 'c')], 'c': [('c', 'd', 'a', 'b'), ('c', 'd', 'b', 'a'), ('c', 'b', 'd', 'a'), ('c', 'a', 'b', 'd')]}

现在,获取每个domain的元素并清除dict,然后循环直到dict为空:

>>> while d:
...     for k, vs in d.items():
...          e = vs.pop()
...          print (e)
...     d = {k: vs for k, vs in d.items() if vs} # clear the dict
...
('b', 'a', 'c', 'd')
('d', 'b', 'a', 'c')
('a', 'd', 'b', 'c')
('c', 'a', 'b', 'd')
('b', 'd', 'c', 'a')
('d', 'b', 'c', 'a')
('a', 'd', 'c', 'b')
('c', 'b', 'd', 'a')
('b', 'c', 'a', 'd')
('d', 'a', 'c', 'b')
('a', 'b', 'c', 'd')
('c', 'd', 'b', 'a')
('b', 'a', 'd', 'c')
('d', 'c', 'a', 'b')
('a', 'b', 'd', 'c')
('c', 'd', 'a', 'b')
('b', 'd', 'a', 'c')
('d', 'a', 'b', 'c')
('a', 'c', 'd', 'b')
('b', 'c', 'd', 'a')
('d', 'c', 'b', 'a')    

输出更加均匀。你知道吗

相关问题 更多 >