Читать содержимое <script>с BeautifulSoup - PullRequest
1 голос
/ 05 ноября 2011

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

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, который отличается для каждого, и я могу выяснить остальное другими способами. Так что, если я смогу найти только те, которые соответствуют этому шаблону, все будет в порядке.


EDIT

В ответ на eyquem я загрузил соответствующие порции до и после того, что хочу pastebin . Я заинтересован в получении значений в pageUrls.

Ответы [ 2 ]

5 голосов
/ 05 ноября 2011

Пожалуйста, введите следующий код и опубликуйте результат.Я напишу регулярное выражение для перехвата данных, которые вы хотите получить.

Примечание: было бы проще, если бы вы опубликовали это в моем письме, и это не обременяло бы 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 ] наличие вкладок или пробелов в конце строки возможно только, но не обязательно.

2 голосов
/ 06 ноября 2011

Просто еще один подход, чтобы дать вам альтернативную точку данных.Вот экстрактор для вашей проблемы, использующий pyparsing вместо регулярных выражений.Возможно, вам будет проще поддерживать его в долгосрочной перспективе:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...