You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用asyncio抓取cian站点经纪人信息遇两类问题求助

Asyncio抓取CIAN站点的问题排查

问题1:异步请求触发VPN验证,同步请求正常

使用aiohttp的全异步请求时,收到站点要求使用VPN的提示,但改用同步urlopen后能正常获取数据。

异步请求代码:

async def async_get_all_realtors(session, url):
    async with session.get(url) as response:
        html = await response.text()

    bsobj = soup(html, 'html.parser')
    
    agent_names = []
    for i in bsobj.findAll('div', {'class': '_9400a595a7--name--ipaRv'}):
        agent_names.append(i.span.text.strip())
    
    return agent_names

修改后的同步请求代码:

async def async_get_all_realtors(url):
    html = urlopen(url)
    bsobj = soup(html, 'html.parser')
    
    agent_names = []
    for i in bsobj.findAll('div', {'class': '_9400a595a7--name--ipaRv'}):
        agent_names.append(i.span.text.strip())
    
    return agent_names

原因与解决方案

站点反爬机制识别了aiohttp的默认请求特征(如缺少浏览器标识的User-Agent),判定为异常请求。解决方法:

  • 给异步请求添加模拟浏览器的请求头,示例:
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
    }
    async with session.get(url, headers=headers) as response:
    
  • 可适当添加请求延迟,避免短时间内发起大量请求触发反爬限制。

问题2:Main函数内打印结果正常,外部await返回空值

完整代码中,main函数内打印all_agent_names显示数据完整,但外部通过await main(url, num_of_pages)获取的结果为空。

完整代码:

from urllib.request import urlopen
import aiohttp
from bs4 import BeautifulSoup as soup
import asyncio
import pandas as pd

url = "https://www.cian.ru/realtors/?dealType=sale&offerType%5B0%5D=flat&regionId=1"

def get_num_pages(url):
    html = urlopen(f"{url}&page=1")
    bsobj = soup(html.read(), 'html.parser')
    return int(bsobj.findAll('span', {'class': '_9400a595a7--content--sGuO7'})[-1].text)

async def async_get_all_realtors(url):
    html = urlopen(url)
    bsobj = soup(html, 'html.parser')
    
    agent_names = []
    for i in bsobj.findAll('div', {'class': '_9400a595a7--name--ipaRv'}):
        agent_names.append(i.span.text.strip())
    
    return agent_names

async def main(url, num_pages):
    tasks = []

    for page_num in range(1, num_pages + 1):
        page_url = f"{url}&page={page_num}"
        task = asyncio.create_task(async_get_all_realtors(page_url))
        tasks.append(task)

    results = await asyncio.gather(*tasks)

    # Here all are Ok this variable contains full information
    all_agent_names = [name for result in results for name in result]

    print(all_agent_names)
    return all_agent_names


num_of_pages = get_num_pages(url)
result = await main(url, num_of_pages) # Empty result, why?

原因与解决方案

  1. 同步阻塞事件循环:在异步函数async_get_all_realtors中使用同步的urlopen,会阻塞整个asyncio事件循环,并发执行时可能导致任务执行异常,虽然main内的print在任务完成后能输出结果,但返回值可能因事件循环状态异常丢失。
  2. Jupyter事件循环特性:Jupyter Notebook自带事件循环,直接使用await可能和任务创建的事件循环存在冲突。

解决方法:

  • 替换同步urlopen为aiohttp的异步请求(结合问题1的请求头设置),避免阻塞事件循环。
  • 在Jupyter中改用asyncio.run()执行主函数,或手动管理事件循环:
    # 替代直接await main(...)
    result = asyncio.run(main(url, num_of_pages))
    
    或者:
    import asyncio
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    result = loop.run_until_complete(main(url, num_of_pages))
    
  • 确保单元格只执行一次result = await main(...),避免变量被重复赋值或事件循环冲突。

内容的提问来源于stack exchange,提问作者Roman Kazmin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:01:12