Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用BS4进行抓取,但解析时HTML会出错_Python_Html_Web_Beautifulsoup_Screen Scraping - Fatal编程技术网

Python 使用BS4进行抓取,但解析时HTML会出错

Python 使用BS4进行抓取,但解析时HTML会出错,python,html,web,beautifulsoup,screen-scraping,Python,Html,Web,Beautifulsoup,Screen Scraping,我在使用BeautifulSoup4和Python3抓取网站时遇到问题。我使用DrySrape来获取HTML,因为它需要启用JavaScript才能显示(但据我所知,它从未在页面本身中使用过) 这是我的代码: from bs4 import BeautifulSoup import dryscrape productUrl = "https://www.mercadona.es/detall_producte.php?id=32009" session = dryscrape.Session(

我在使用BeautifulSoup4和Python3抓取网站时遇到问题。我使用DrySrape来获取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
内容,但是:

type(container3)
返回:

bs4.element.ResultSet
它与
类型(container1)
相同,但长度为0

所以我想在寻找我的
标签之前知道我得到了什么
container3
,所以我把它写到了一个文件中

container3 = soup.find("div","contenido")
soup_file.write(container3.prettify())
下面是指向该文件的链接:


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

以下是更新后的解决方案:

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)
对此的响应为您提供了
请启用JavaScript以查看页面内容。
消息。但是,它还包含必要的
隐藏的
数据,这些数据由使用javascript的浏览器发送,可以从开发人员工具的网络选项卡中看到

TS015fc057_id: 3
TS015fc057_cr: a57705c08e49ba7d51954bea1cc9bfce:jlnk:l8MH0eul:1700810263
TS015fc057_76: 0
TS015fc057_86: 0
TS015fc057_md: 1
TS015fc057_rf: 0
TS015fc057_ct: 0
TS015fc057_pd: 0
其中,第二个(长字符串)由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)

你能用硒来做这个吗?@drec4s是的,我能。我为什么要这样做?selenium对这种情况的设计是否有点过头了?编辑了我的答案。它能工作,但有点慢。也许,选择一个替代库来运行python中的JS代码会给您带来更好的性能。试试PyV8。@Mahesh非常感谢!!我不在乎速度,也许我可以晚些时候再考虑。我明天就试试。@Mahesh一切都好。再次非常感谢。我是一个新的刮片专家,对这个问题一无所知。嗨,我不能复制你的结果。I get:TypeError:Response类型的对象没有len()您正在使用请求会话吗?谢谢,如果这是一个微不足道的问题,我很抱歉。@EngineeringStudent您可能正在将响应对象传递给len。首先使用它创建一个soup对象,然后导航树
soup=BeautifulSoup(r.content,'lxml')
然后尝试我答案中的语句。为了清晰起见,我将编辑我的答案以包含该语句。让我向您展示我正在运行的完整代码和完整输出:我得到的是一个页面,它要求我启用javascript以显示我想要放弃的内容。e非常感谢您的帮助。@EngineeringStudent我正在查看它。那时候它对我有用。我一弄明白就编辑答案。