我一直在努力阅读以下网站的来源:
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。我如何使用正则表达式提取此信息?
如果没有简单的方法来获取所有,以下内容可能是妥协。 values
的大多数的格式为"string1/xxxx/string2"
,其中xxxx
是一些随机的SHA哈希值,每个哈希值都不同,我可以通过其他方式找出其余部分。所以,如果我只能找到符合这种模式的那些,那就应该没问题了。
修改
为了回应eyquem,我已经在我想要pastebin之前和之后上传了相关部分。我有兴趣检索pageUrls
中的值。
答案 0 :(得分:5)
请执行以下代码并发布结果。我将编写一个正则表达式来捕获您想要获取的数据。
Nota:如果你在我的电子邮件中发布它会更容易,它不会妨碍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文本不能用正则表达式进行分析的人,我说:ùù&amp;ùè-_,sp *μùy43é'## {[|:ù%yy~é“&amp;'[[é(+ F +) “§.N/ .M %% iyuo£$$ö!!!!sskrftttt§!!)
如果文本按照看似有规律的方式进行组织,您甚至不需要正则表达式来分析它:
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')
为了使代码相对于文件中内容的变化更安全,您也可以使用正则表达式:
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 )
为了使这两个代码能够正常运行,网址中一定不能有','。
在第一段代码中,网址中也不得有']'。但我证实:在Windows上,分配名称可以包含']'
我编写了第二个代码的正则表达式模式,以避免由于网址中的','或']'引起的问题:这与正则表达式],[\t ]*$
的结尾部分有关,它要求']'字符必须是只有空格或标签,直到行尾。由于[\t ]
之后的星号'*',只能在行尾添加制表符或空格,而不是强制性的。
答案 1 :(得分:2)
另一种方法是为您提供替代数据点。这是使用pyparsing而不是regex解决问题的提取器。从长远来看,您可能会发现这更容易维护:
from pyparsing import Literal, quotedString, removeQuotes, delimitedList
# automatically strip quotes from quoted strings
# quotedString matches single or double quotes
quotedString.setParseAction(removeQuotes)
# define a pattern to extract the pageUrls: entry
pageUrlsSpec = Literal('pageUrls:') + '[' + delimitedList(quotedString)('urls') + ']'
for pageUrls in pageUrlsSpec.searchString(ss):
for url in pageUrls.urls:
print url
打印:
/blog/35318264c9a98faf79965c270ac80c5606774df1/data.pdf
/blog/da6645f6e22bf5f75974dc7eed5fcd6160d6b51e/data.pdf
/blog/6f90f101115140727c43cadee0b9e17881403a63/data.pdf
/blog/333584fc2850d1a1f97a0a7bf8c5a12e684856bf/data.pdf
/blog/9a018ecc48a37a9247a6404fd83e085384b445aa/data.pdf