使用AsyncIO爬取REI网站时的生成器访问错误排查
解决AsyncIO爬虫中asyncio.gather结果解析的AttributeError问题
问题核心
你踩了个常见的坑:asyncio.gather(*tasks) 返回的是所有任务结果组成的列表——哪怕只爬1页,results也是[HTMLParser对象],而非单个HTMLParser实例。直接把列表传给parse_search_page,函数里调用html.css()必然触发AttributeError,因为列表根本没有css方法。另外fetch_html在请求失败时会返回False,不处理这种无效结果也会导致后续解析报错。
修正代码
重点修改main函数的结果处理逻辑,遍历results列表并过滤无效结果:
from typing import Any import asyncio import httpx from selectolax.parser import HTMLParser from urllib.parse import urljoin async def fetch_html(client: httpx.AsyncClient, url: str, **kwargs) -> Any: headers = { "User-Agent": "替换成你的UA,否则会403" } if kwargs.get("page"): resp = await client.get( url=url + str(kwargs.get("page")), follow_redirects=True, headers=headers ) else: resp = await client.get(url=url, follow_redirects=True, headers=headers) try: resp.raise_for_status() except httpx.HTTPStatusError as exc: print( f"请求出错 {exc.response.status_code},目标地址:{exc.request.url!r},已超出页面限制" ) return False html = HTMLParser(html=resp.text) return html def extract_text(html: HTMLParser, sel: str): try: text = html.css_first(sel).text() return text except AttributeError: return None def parse_search_page(html: HTMLParser): products = html.css("li.VcGDfKKy_dvNbxUqm29K") for product in products: yield urljoin("https://www.rei.com/", product.css_first("a").attributes["href"]) async def main(): async with httpx.AsyncClient(http2=True) as client: tasks = [] rei_url = "https://www.rei.com/c/camping-and-hiking/f/scd-deals?page=" # 这里可以修改range爬多页,比如range(1, 5) for i in range(1, 2): tasks.append(asyncio.create_task(fetch_html(client, rei_url, page=i))) results = await asyncio.gather(*tasks) # 关键改动:遍历结果列表,过滤无效值,逐个解析页面 links = [] for html in results: if html is not False: links.extend(parse_search_page(html)) for link in links: print(link) if __name__ == "__main__": asyncio.run(main())
额外说明
- 不需要把
parse_search_page改成异步:HTML解析是CPU密集型操作,异步IO只适合网络请求这类IO密集型任务,同步解析反而更高效。 - 多页爬取兼容:如果后续要爬多页,直接修改
range(1, N)即可,代码会自动收集所有页面的商品链接。 - 必须替换UA:网站会拦截默认UA,务必把
fetch_html里的User-Agent改成你的浏览器真实UA。
内容的提问来源于stack exchange,提问作者Adrian Fletcher
相关产品推荐
相关产品推荐

