Я пытаюсь прочитать источник веб-сайта со следующим:
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 = 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, я загрузил соответствующие части до и после того, что я хочу использовать пастебин. Мне интересно получить значения в pageUrls
.
Пожалуйста, выполните следующий код и опубликуйте результат. Я напишу регулярное выражение, чтобы поймать данные, которые вы хотите получить.
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)))
Регулярное выражение по крайней мере в 20 раз быстрее, чем использование BeautifulSoup для анализа текста.
Я говорю "анализировать" НЕ "разобрать",
(для людей, считающих, что текст HTML не должен анализироваться с помощью регулярного выражения, я говорю: ùù & ùè -_, sp * μùy43é '## {[|: ù% yy ~ é "&' [[é (+ 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 )
Для хорошего функционирования двух кодов не должно быть "," в URL-адресах.
В первом коде также не должно быть "]" в URL-адресах. Но я подтвердил: в Windows имена репертуаров могут иметь "]" в них.
Я написал шаблон регулярного выражения второго кода, чтобы избежать проблем из-за ',' или ']' в URL-адресах: это с конечной частью регулярного выражения ],[\t ]*$
которая требует, чтобы ']' символ должен следовать только пробелами или вкладками до конца строки. Из-за звезды '*' после [\t ]
наличие вкладок или пробелов в конце строки возможно только, а не обязательно.
i
в str(i)
выше? Вы str(line)
виду str(line)
?
Еще один подход, чтобы дать вам альтернативную точку данных. Вот экстрактор для вашей проблемы, используя 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