Читать содержимое <script> с BeautifulSoup

1

Я пытаюсь прочитать источник веб-сайта со следующим:

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.

  • 0
    Кроме того, прежде чем кто-то спросит о реальном веб-сайте, он доступен только внутри, так что не очень поможет в этом вопросе ...
  • 0
    Есть несколько парсеров JavaScript / ECMAScript для python. Модификация одного из них для извлечения определенной информации - это труд, который будет уродливым, но не слишком сложным.
Показать ещё 4 комментария
Теги:
beautifulsoup

2 ответа

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)))

Регулярное выражение по крайней мере в 20 раз быстрее, чем использование BeautifulSoup для анализа текста.

Я говорю "анализировать" НЕ "разобрать",
(для людей, считающих, что текст 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 имена репертуаров могут иметь "]" в них.
Я написал шаблон регулярного выражения второго кода, чтобы избежать проблем из-за ',' или ']' в URL-адресах: это с конечной частью регулярного выражения ],[\t ]*$ которая требует, чтобы ']' символ должен следовать только пробелами или вкладками до конца строки. Из-за звезды '*' после [\t ] наличие вкладок или пробелов в конце строки возможно только, а не обязательно.

  • 0
    Какая у тебя переменная i в str(i) выше? Вы str(line) виду str(line) ?
  • 0
    Ой, простите. Я исправляю
Показать ещё 11 комментариев
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
  • 0
    Это на самом деле выглядит намного аккуратнее. Я попробую оба подхода и рассмотрю вопрос об их принятии, если мне действительно будет легче (это, безусловно, выглядит так!). Спасибо :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню