【问题标题】:Scraping text injected by Javascript using BeautifulSoup使用 BeautifulSoup 抓取 Javascript 注入的文本
【发布时间】:2020-06-29 04:50:16
【问题描述】:

我想从网页中抓取日期,并且日期的文本(在脚本标记之后)由 JavaScript 注入: 我只想用 Beautifulsoup 来刮它,而不是硒

<div class="row">
    <span class="LName"><a target="_blank" href="http://google.com">[me too]</a></span>
    <script language="Javascript" type="text/javascript">formatDate('2020,5,23,09,00,00',1)</script>6/23/2020&nbsp;10:00&nbsp;Tuesday
</div>

这是用于尝试抓取日期文本的代码:

headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0'}
r = requests.get(u, headers=headers)
soup = BeautifulSoup(r.content, 'html.parser')

我试试:

soup.select('div.row > script')[0].get_text()

返回:

"formatDate('2020,5,23,09,00,00',1)" 

和:

soup.select('div.row')[0].get_text()

返回:

"\n[me too] formatDate('2020,5,23,09,00,00',1)\n" 

当我使用 Chrome 检查标签时,我可以看到脚本标签后面的日期文本

当我执行时:

soup.select('div.row')

它返回没有日期文本的标签

我只想用 Beautifulsoup 刮,而不是硒

【问题讨论】:

  • 您需要一个能够理解 javascript 文本的 javascript 引擎。但不幸的是,美丽的汤并没有这样做

标签: python web-scraping beautifulsoup


【解决方案1】:
import re
from bs4 import BeautifulSoup
from datetime import datetime


txt = '''<div class="row">
    <span class="LName"><a target="_blank" href="http://google.com">[me too]</a></span>
    <script language="Javascript" type="text/javascript">formatDate('2020,5,23,09,00,00',1)</script>6/23/2020&nbsp;10:00&nbsp;Tuesday
</div>'''

soup = BeautifulSoup(txt, 'html.parser')
year, month, day, hour, minutes, sec, *_ = map(int, re.findall(r'\d+', soup.select_one('div.row > script').contents[0]))
d = datetime(year=year, month=month + 1, day=day, hour=hour + 1, minute=minutes, second=sec)
print(datetime.strftime(d, '%m/%d/%Y %H:%M %A'))

打印:

06/23/2020 10:00 Tuesday

【讨论】:

  • 它返回一个错误:TypeError: 'module' object is not callable after I run datetime(year=year, month=month + 1, day=day, hour=hour + 1, minute=minutes , second=sec)
  • @Ravanelli 你必须做from datetime import datetime,而不仅仅是import datetime module
【解决方案2】:

据我了解,BS 根本不渲染 Javascript。我使用 Selenium 抓取内容,然后使用 BS 进行解析。如果你坚持不使用 selenium,还有其他包会先渲染页面,然后你将其输入 BeautifulSoup 进行解析。

试试:https://github.com/makinacorpus/spynner 幻影JS

【讨论】:

    【解决方案3】:

    如果您可以依赖始终使用formatDate() 函数生成的日期并且可以采用日期显示格式,那么您可以像您一样使用 BeautifulSoup 提取调用,然后使用正则表达式将其解析出来:

    import re
    date_call = soup.select('div.row > script')[0].get_text()
    year, month, day, hour, minutes, seconds, dow = re.search(r"formatDate\('(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)',(\d)\)", date_call).groups()
    

    然后变量将为您提供重建日期所需的组件:

    dow_map = {str(i):dow for i, dow in enumerate(['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'])}
    date_text = f'{month}/{day}/{year} {h}:{m} {dow_map[dow]}'
    

    【讨论】:

    • 问题是通话日期总是落后一个月零一小时
    • 如果总是这样,那么您可以在 date_text 作业中使用 month+1 和 hour+1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2020-11-10
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多