【问题标题】:Can't get rid of some error page which shows up while using asyncio无法摆脱使用 asyncio 时出现的一些错误页面
【发布时间】:2020-09-30 21:12:00
【问题描述】:

我正在尝试使用文本文件中已有的一些链接来提取不同属性的地址。我已经使用 asyncio 库创建了这个脚本。该脚本运行良好,直到遇到该站点抛出的这种类型的page。我还检查了实施代理,但没有运气。虽然它肯定不是验证码页面,但我在使用 asyncio 时经过几次请求后最终得到了该页面。仅供参考,当我去 requests 模块时,我没有遇到那个页面。

我怎样才能摆脱那个错误页面?

这是我在文本文件中使用的几个urls

我试过了:

import asyncio
import aiohttp
import random
import requests
from bs4 import BeautifulSoup

async def get_text(session,url):
    async with session.get(url,ssl=False) as resp:
        assert resp.status == 200
        print("----------",str(resp.url))
        if "Error" in str(resp.url):raise
        return await resp.read()

async def get_info(sem,session,link):
    async with sem:
        r = await get_text(session,link)          
        soup = BeautifulSoup(r,"html.parser")
        try:
            address = soup.select_one("h1#mainaddresstitle").get_text(strip=True)
        except AttributeError: address = ""
        print(address)

async def main():
    sem = asyncio.Semaphore(5)
    with open("link_list.txt","r") as f:
        link_list = [url.strip() for url in f.readlines()]
        
    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as session:
        await asyncio.gather(
            *(get_info(sem,session,item) for item in link_list)
        )

if __name__ == '__main__':
    asyncio.run(main())

PS当脚本超过速率限制时,它应该会遇到像/Property/UsageValidation这样的页面,但不是 /Property/Error/?id=14e53e71-11b1-4f5e-a88c-f8a4721de99e

【问题讨论】:

  • 我猜你在某种程度上受到了速率限制,因为你只有在异步发出所有请求时才能获得这些页面。当您的脚本遇到该页面时,您究竟希望您的脚本做什么?重试请求?
  • 我不想首先遇到该页面,因为我在使用请求时看不到该页面。我已经提到,即使我实现了代理,我仍然会遇到该页面。所以,我非常怀疑这是因为速率限制。顺便说一句,当网站不喜欢任何机器人时,它就会开始抛出验证码。
  • 你被限速了。

标签: python python-3.x web-scraping python-asyncio


【解决方案1】:

我已尝试通过将您共享的相同 URL 复制到源文件中来重现您的问题。通过这样做,我想模仿一组更大的不同 url 的爬行。这是我学到的。

  • 您似乎确实受到了速率限制。至少我会处理您发布的代码。
  • 即使我使用 VPN 或代理,UsageValidation 页面也会弹出。
  • 我尝试限制每个主机的连接数和/或连接总数,但无济于事。
  • 在协同程序之间设置延迟只会延长我撞到UsageValidation 墙之前的时间。请注意,我一遍又一遍地点击相同的网址,所以这可能不具有代表性。

这是我设法获得最成功响应的代码:

import aiohttp
import asyncio

from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-US,en;q=0.9,pl;q=0.8",
}


async def get_text(session, url):
    async with session.get(url) as resp:
        assert resp.status == 200
        print("----------", resp.url)
        return await resp.read()


async def get_info(sem, session, link):
    async with sem:
        r = await get_text(session, link)
        soup = BeautifulSoup(r, "html.parser")
        try:
            address = soup.select_one("h1#mainaddresstitle").get_text(strip=True)
            await asyncio.sleep(2)
        except AttributeError:
            address = ""
        print(address)


async def main():
    sem = asyncio.Semaphore(2)
    conn = aiohttp.TCPConnector(limit_per_host=2, limit=2)

    with open("source.txt") as f:
        link_list = [url.strip() for url in f.readlines()]

    async with aiohttp.ClientSession(
            connector=conn,
            headers=headers,
            timeout=aiohttp.ClientTimeout(total=5),
    ) as session:
        await asyncio.gather(
            *(get_info(sem, session, item) for item in link_list)
        )


if __name__ == '__main__':
    asyncio.run(main())

想法和解决方案:

  • 停止使用数十个甚至数百个并发请求来打击这个(或任何其他)网站。为什么?因为从本质上讲,您所做的是DoS attack,因为您尝试尽可能快且尽可能频繁地连接到服务器。
  • 通过在 SO 上共享代码,它变成了distributed denial-of-service。对于大型服务,如 LinkedIn 或 Facebook,这可能几乎不引人注意,但对于较小的服务器,这可能是危险的。话虽如此,即使是大公司也有严格的反抓取政策和缓解技术。
  • 在发送另一个请求之前至少等待一秒钟。所需的暂停可能在robots.txt 中定义为Crawl-delay,但从您的名字来看,您已经知道了。
  • 移除多线程或至少限制线程数。
  • 如果您已经访问过某个网址,请不要一次又一次地点击它。做一次你的工作,但要把它做好。
  • 使用重试策略编写缓慢的顺序爬虫/爬虫。为什么?因为,您的爬虫/爬虫代码的主要目标应该是保持低调。最好慢慢做完成工作,而不是在几次请求和/或最终禁止您的 IP 后惨遭失败。
  • 如果有 API,请使用 API。

【讨论】:

  • 感谢您的回答和建议@baduker。使用上面的脚本,我会得到相应的结果,直到出现包含/Property/Error/ 的链接。一旦该错误链接开始发挥作用,我无论如何都无法摆脱它。包含/Property/UsageValidation 的链接不存在绕过的问题,我一开始就能够做到这一点。我只提到了这个链接UsageValidation作为对我收到的评论的回复。
猜你喜欢
  • 2021-01-07
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
  • 2019-04-30
  • 1970-01-01
相关资源
最近更新 更多