我有下面的代码。它打开了无头浏览器,我也看到页面滚动,但解析方法中的响应对象没有任何HTML。当我不使用自动滚动时,这个蜘蛛工作得很好。
该代码应该只提取产品名称和产品价格从这个网站。
import scrapy
import re
from scrapy_playwright.page import PageMethod
from bs4 import BeautifulSoup
def should_abort_request(req):
if req.resource_type == "image":
return True
if req.method.lower() == 'post':
return True
return False
scrolling_script = """
const scrolls = 8
let scrollCount = 0
// scroll down and then wait for 5s
const scrollInterval = setInterval(() => {
window.scrollTo(0, document.body.scrollHeight)
scrollCount++
if (scrollCount === numScrolls) {
clearInterval(scrollInterval)
}
}, 5000)
"""
class AuchanSpider(scrapy.Spider):
name = 'auchan'
custom_settings = {
'PLAYWRIGHT_ABORT_REQUEST': should_abort_request
}
start_urls = ['https://zakupy.auchan.pl/shop/list/8029?shType=id']
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url=url,
callback=self.parse,
meta={
"playwright": True,
"playwright_include_page": True,
"playwright_page_methods": [
PageMethod("evaluate", scrolling_script),
#PageMethod("wait_for_timeout", 30000),
PageMethod("wait_for_selector", "._1E5b _2I59 _1wkJ _3YFw igxN _7Zx6 Eb4X _390_"),
PageMethod("wait_for_selector", "._1E5b _2I59 _1wkJ _3YFw igxN _7Zx6 Eb4X _390_:nth-child(60)")
],
},
errback=self.close_page,
cb_kwargs=dict(main_url=url, page_number=0),
)
async def parse(self, response, main_url, page_number):
soup = BeautifulSoup(response.text, 'html.parser')
product_containers = soup.find_all('div', class_='_1E5b _2I59 _1wkJ _3YFw igxN _7Zx6 Eb4X _390_')
for product_container in product_containers:
price = product_container.find(class_='_1-UB _1Evs').get_text()
price = re.sub(r"[\n\t\s]*", "", price)
yield {
'productName': product_container.find(class_='_1DGZ').get_text(),
'price': price
}
async def close_page(self, failure):
page = failure.request.meta["playwright_page"]
await page.close()
字符串
2条答案
按热度按时间zf2sa74q1#
我会比你更直接地处理这个问题。不需要BeautifulSoup,因为Playwright已经可以在live页面上选择元素了。我也不确定Scrapy是否是必要的,但是如果你愿意,你可以将下面的Playwright代码改编为Scrapy:
字符串
这段代码会删除cookie和广告横幅,然后按PageDown直到没有更多的记录可供获取。我只是从DOM中提取标题和链接,但如果需要,您可以添加更多信息。
请注意,我使用的选择器更简单。选择器中的假设越多,如果任何一个不成立,它就越有可能失败。在您的例子中,尽管问题是使用空格而不是
.
来标识一个元素上的多个类(空格表示祖先),一开始就不要使用这么多的类来避免混淆。首先在浏览器控制台中检查你的选择器,请记住,这并不能保证它们在不同的环境下都能在Playwright中工作。浏览器可以生成示例选择器。尽管这些选择器通常过于具体,但它们至少是有效的,并且可以改进以更加可靠。此外,我意识到使用页面底部的文本“Zaanadowano 361 produkt(y)na 361”来确定所有记录何时被抓取可能更好,但我将把它作为练习。
另一种方法是拦截请求而不是抓取文档,这会提供更多的数据(提供的页面约为2 MB):
型
然后,您可以使用jq循环JSON以提取您想要的任何信息,例如名称:
型
在Python中:
型
有一个列表comp:
型
请注意,上面的版本遗漏了记录的第一页,这可以从DOM中抓取,也可以使用从另一个API请求复制的头部进行单独的请求。
但是,一旦进入请求拦截领域,您可以劫持一个请求到他们的API,并将其连接以返回500个项目,从而更快速轻松地收集所有数据:
型
这个结构可以如下处理,使用抓取名称的例子:
型
在Python中:
型
vwoqyblh2#
我想明白了。问题出在
wait_for_selector
上。div中不应该有'空格'。相反,空格应该替换为'.'。这就是wait_for_selector
的样子。PageMethod("wait_for_selector", "._1E5b._2I59._1wkJ._3YFw.igxN._7Zx6.Eb4X._390_"),