Skip to main content
 首页 » 编程设计

python之使用 BeautifulSoup 读取 <script> 的内容

2025年05月04日15sharpest

我一直在尝试使用以下内容阅读网站的来源:

import urllib2 
from BeautifulSoup import BeautifulSoup 
 
url     = 'http://www.myurl.com/' 
headers = {'User-Agent' : 'Mozilla/5.0'} 
request = urllib2.Request(url,None,headers) 
soup    = BeautifulSoup(urllib2.urlopen(request).read()) 

我进一步将其缩小为 scriptResults = soup('script',{'type' : 'text/javascript'})。其内容示例如下:

scriptResults = [<script type="text/javascript"> ... </script>, 
                 ..., 
                 <script type="text/javascript"> 
                     //comment 1 
                     $(function () { 
                     //comment 2 
                     var True = true, False = false; 
                         func.start({ 
                             token1 : "...", 
                             token2 : [...], 
                             ... 
                             tokenN : ["value1","value2",...,"valueK"], 
                             ... 
                         }) 
                     }) 
                 </script>, 
                 ... 
                 ] 

现在我有兴趣提取 tokenN 中的值。我知道它在整个文档中是独一无二的,并且存在于我尝试阅读的所有网页中。此外,scriptResults 中的结果数量可能会有所不同,标记的数量也会有所不同,因此我无法使用位置索引来访问它。另外,我意识到 BeautifulSoup 是一个 HTML 解析器,不解析 JS。我将如何使用正则表达式提取此信息?

如果没有一种简单的方法来全部,则可以采用以下折衷方案。 大多数值的格式都是"string1/xxxx/string2",其中xxxx是一些随机的SHA每个哈希值都不同,我可以通过其他方式找出其余部分。所以如果我只能找到符合这种模式的那些,应该没问题。


编辑

为了回应eyquem,我已经上传了我想要的前后的相关部分pastebin .我对检索 pageUrls 中的值很感兴趣。

请您参考如下方法:

请执行以下代码并发布结果。我会写一个正则表达式来捕获你想要获取的数据。

注意:如果你把它贴在我的电子邮件中会更容易,它不会占用 SO 内存

sock = urllib2.urlopen(request) 
ch = sock.read() 
sock.close() 
 
print '\n'.join(str(i) + '  ' + repr(line) 
                for i,line in enumerate(ch.splitlines(True))) 

正则表达式比使用 BeautifulSoup 分析文本至少快 20 倍。

我说的是“分析”而不是“解析”
(对于那些认为不能用正则表达式分析 HTML 文本的人,我说:ùù&ùè-_, sp*µùy43é' ##{[|:ù %yy~é"&'[[é(+F+"§. N/.M%%iyuo£$$ö!!!! sskrftttt §!!)

编辑1

如果文本像看起来一样有规律地组织,您甚至不需要正则表达式来分析它:

from io import StringIO 
 
ss = '''<input type="hidden" name="__FOO" id="__FOO" value="garble" /> 
 
<script type="text/javascript"> 
//<![CDATA[ 
$(function () { 
    // convert to  
    var True = true, False = false; 
 
    manatee.start({ 
        pageIDs: ["16798", "16799", "16800", "16801", "16802"], 
        userNames: ["Alice", "Bob", "Carol", "Dave", "Eve"], 
        wordCounts: [77,23,64,89,93], 
        linkCounts: [2,0,3,1,4], 
        pageUrls: ["","/blog/35318264c9a98faf79965c270ac80c5606774df1/data.pdf","/blog/da6645f6e22bf5f75974dc7eed5fcd6160d6b51e/data.pdf","/blog/6f90f101115140727c43cadee0b9e17881403a63/data.pdf","/blog/333584fc2850d1a1f97a0a7bf8c5a12e684856bf/data.pdf","/blog/9a018ecc48a37a9247a6404fd83e085384b445aa/data.pdf"], 
 
        toolbar: { 
            id: "ManateeToolbar", 
            buttons: [ 
                { 
                    id: "ManateeBrowser", 
                    text: "Enter Fullscreen", 
                    toggleText: "Escape Fullscreen" 
                } 
            ] 
        } 
 
    }); 
}); 
//]]> 
</script> 
 
<script type="text/javascript">var blah</script>''' 
 
 
 
simili_file = StringIO(ss) 
 
for line in simili_file: 
    if line[0:13] == '\t\tpageUrls: [': 
        urls = tuple(el[1:-1] for el in line[13:line.find(']')].split(',') if el[1:-1])            
    print( urls ) 

结果

('/blog/35318264c9a98faf79965c270ac80c5606774df1/data.pdf', 
'/blog/da6645f6e22bf5f75974dc7eed5fcd6160d6b51e/data.pdf',  
'/blog/6f90f101115140727c43cadee0b9e17881403a63/data.pdf',  
'/blog/333584fc2850d1a1f97a0a7bf8c5a12e684856bf/data.pdf',  
'/blog/9a018ecc48a37a9247a6404fd83e085384b445aa/data.pdf') 

编辑2

为了使代码相对于文件中内容的变化更安全,您也可以使用正则表达式:

ss = '''<input type="hidden" name="__FOO" id="__FOO" value="garble" /> 
 
<script type="text/javascript"> 
//<![CDATA[ 
$(function () { 
    // convert to  
    var True = true, False = false; 
 
    manatee.start({ 
        pageIDs: ["16798", "16799", "16800", "16801", "16802"], 
        userNames: ["Alice", "Bob", "Carol", "Dave", "Eve"], 
        wordCounts: [77,23,64,89,93], 
        linkCounts: [2,0,3,1,4], 
        pageUrls: ["","/blog/35318264c9a98faf79965c270ac80c5606774df1/data.pdf","/blog/da6645f6e22bf5f75974dc7eed5fcd6160d6b51e/data.pdf","/blog/6f90f101115140727c43cadee0b9e17881403a63/data.pdf","/blog/333584fc2850d1a1f97a0a7bf8c5a12e684856bf/data.pdf","/blog/9a018ecc48a37a9247a6404fd83e085384b445aa/data.pdf"], 
 
        toolbar: { 
            id: "ManateeToolbar", 
            buttons: [ 
                { 
                    id: "ManateeBrowser", 
                    text: "Enter Fullscreen", 
                    toggleText: "Escape Fullscreen" 
                } 
            ] 
        } 
 
    }); 
}); 
//]]> 
</script> 
 
<script type="text/javascript">var blah</script>''' 
 
 
import re 
 
 
regx = re.compile('^\t*pageUrls[\t ]*:[\t ]*\[(.*?)\],[\t ]*$',re.MULTILINE) 
 
for mat in regx.finditer(ss): 
    urls = tuple(el[1:-1] for el in mat.group(1).split(',') if el[1:-1]) 
    print( urls ) 

为了两个代码的良好运行,url 中不能有','。

在第一个代码中,url 中也不能有']'。但我验证过:在 Windows 上,轨道名称中可以包含 ']'。
我编写了第二个代码的正则表达式模式,以避免因网址中的 ',' 或 ']' 引起的问题:这是正则表达式 ],[\t ]*$ 的结尾部分这要求 ']' 字符后面只能跟空格或制表符,直到行尾。由于 [\t ] 之后的星号“*”,制表符或空格在行尾的存在只是可能的,而不是强制性的。