使用BS4进行抓取,但HTML在解析时会变得一团糟

2024-09-29 03:36:59 发布

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

我在用BeautifulSoup4和Python3抓取网站时遇到了问题。我使用dryscrape来获取HTML,因为它需要启用JavaScript才能显示(但据我所知,它从未在页面中使用过)。在

这是我的代码:

from bs4 import BeautifulSoup
import dryscrape

productUrl = "https://www.mercadona.es/detall_producte.php?id=32009"
session = dryscrape.Session()
session.visit(productUrl)
response = session.body()
soup = BeautifulSoup(response, "lxml")
container1 = soup.find("div","contenido").find("dl").find_all("dt")
container3 = soup.find("div","contenido").find_all("td")

现在我想阅读container3内容,但是:

^{pr2}$

退货:

bs4.element.ResultSet

它与type(container1)相同,但它的长度是0!在

所以我想知道在查找我的<td>标记之前,我得到了container3的什么,所以我把它写到了一个文件中。在

container3 = soup.find("div","contenido")
soup_file.write(container3.prettify())

下面是指向该文件的链接:https://pastebin.com/xc22fefJ

就在我要刮桌子之前,一切都搞砸了。我不明白为什么,看看Firefox的URL源代码,一切看起来都很好。在


Tags: httpsimportdivresponsesessionallfindsoup
1条回答
网友
1楼 · 发布于 2024-09-29 03:36:59

以下是更新的解决方案:

url = 'https://www.mercadona.es/detall_producte.php?id=32009'

rh = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Connection': 'keep-alive',
    'Host': 'www.mercadona.es',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}

s = requests.session()
r = s.get(url, headers = rh)

对此的响应给出Please enable JavaScript to view the page content.消息。但是,它还包含浏览器使用javascript发送的必要的hidden数据,可以从开发人员工具的network选项卡中看到。在

^{pr2}$

其中,第二个(长字符串)是由javascript生成的。我们可以使用js2py这样的库来运行代码,它将返回请求中传递的所需字符串。在

soup = BeautifulSoup(r.content, 'lxml')
script = soup.find_all('script')[1].text

js_code = re.search(r'.*(function challenge.*crc;).*', script, re.DOTALL).groups()[0] + '} challenge();'
js_code = js_code.replace('document.forms[0].elements[1].value=', 'return ')

hidden_inputs = soup.find_all('input')
hidden_inputs[1]['value'] = js2py.eval_js(js_code)

fd = {i['name']: i['value'] for i in hidden_inputs}

rh = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Referer': 'https://www.mercadona.es/detall_producte.php?id=32009',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'en-US,en;q=0.9',
    'Connection': 'keep-alive',
    'Content-Length': '188',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Cache-Control': 'max-age=0',
    'Host': 'www.mercadona.es',
    'Origin': 'https://www.mercadona.es',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}

# NOTE: the next one is a POST request, as opposed to the GET request sent before
r = s.post(url, headers = rh, data = fd)
soup = BeautifulSoup(r.content, 'lxml')

结果如下:

>>> len(soup.find('div', 'contenido').find_all('td'))
70
>>> len(soup.find('div', 'contenido').find('dl').find_all('dt'))
8

编辑

显然,javascript代码只需要运行一次。结果数据可用于多个请求,如下所示:

for i in range(32007, 32011):
    r = s.post(url[:-5] + str(i), headers = rh, data = fd)
    soup = BeautifulSoup(r.content, 'lxml')
    print(soup.find_all('dd')[1].text)

结果:

Manzana y plátano 120 g
Manzana y plátano 720g (6x120) g
Fresa Plátano 120 g
Fresa Plátano 720g (6x120g)

相关问题 更多 >