使用漂亮的汤来抓取数据时出现html标签问题

时间:2013-01-02 12:08:47

标签: python-2.7 html-parsing screen-scraping beautifulsoup html

通用代码:

# -*- coding: cp1252 -*-
import csv
import urllib2
import sys
import time
from bs4 import BeautifulSoup
from itertools import islice

page = urllib2.urlopen('http://www.vodafone.de/privat/tarife/red-smartphone-tarife.html').read()
soup = BeautifulSoup(page)
prices = soup.findAll('div', {"class": "price"})

在此之后我尝试使用以下代码来获取数据: 代码1:

for price in prices:
    print unicode(price.string).encode('utf8')

输出1:无输出,代码运行时没有任何错误,并且不打印任何内容。

代码2:

for price in prices:
    textcontent3= u' '.join(price.stripped_strings)
    if textcontent3:
        print textcontent3

输出2:无输出,与输出1中的情况相同。

代码3:

for price in prices:
    fonttag = price.find('div')
    if fonttag is not None:
        print unicode(fonttag.string).encode('utf8').strip()

Output3:无输出,与Output1

相同

在此之后我尝试打印html的相关部分:

代码4:

print prices

输出4:

</span></div>, <div class="price">
<span id="price"><br/>
</span></div>, <div class="price">
<span id="price"><br/>
</span></div>]

从Output4可以看出,没有价格值出现在html美丽的汤中为我刮痧。在网页上,这个html结构如下所示:

<div class="price"><span id="price">49,90 €</span><br>einmalig</div>

美丽的汤没有提取html页面中提到的价格值,因此我无法抓取价格数据。 请帮我解决这个问题&amp;请原谅我的无知,因为我不熟悉编程。

1 个答案:

答案 0 :(得分:1)

该页面使用大型JavaScript结构来加载价格。您只能加载该结构:

scripts = soup.find_all('script')
script = next(s.text for s in scripts if s.string and 'window.rates' in s.string)
datastring = script.split('phones=')[1].split(';window.')[0]

这会产生一个庞大的JavaScript结构,从:

开始
{sku844082:{name:"Samsung Galaxy SII",image:"/images/m677391_300468.jpg",deliveryTime:"Vorauss. verf&#252;gbar ab Anfang Januar",sku1444291:{p:"prod954312",e:"19.90"},sku1444286:{p:"prod954312",e:"19.90"},sku1444283:{p:"prod954312",e:"39.90"},sku1444275:{p:"prod954312",e:"59.90"},sku1104261:{p:"prod954312",e:"99.90"}},sku894279:{name:"BlackBerry Torch 9810",image:"/images/m727477_300464.jpg",deliveryTime:"Lieferbar innerhalb 48 Stunden",sku1444275:{p:"prod1004495",e:"179.90"},sku1104261:{p:"prod1004495",e:"259.90"},sku1444291:{p:"prod1004495",e:"29.90"},sku1444286:{p:"prod1004495",e:"29.90"},sku1444283:{p:"prod1004495",e:"49.90"}},sku864221:{name:"BlackBerry Bold 9900",image:"/images/m707491_300465.jpg",deliveryTime:"Lieferbar innerhalb 48 Stunden",sku1444275:{p:"prod974431",e:"129.90"},sku1104261:{p:"prod974431",e:"169.90"},sku1444291:{p:"prod974431",e:"49.90"},sku1444286:{p:"prod974431",e:"49.90"},sku1444283:{p:"prod974431",e:"89.90"}}

不幸的是,这不能直接用json模块加载;虽然有效的JavaScript,但没有引用键,它是无效的JSON。您需要使用正则表达式来进一步清理它,或直接从该字符串中获取p:"someprice"信息。

幸运的是,结构可以通过少量正则表达法来修复:

import re
import json

datastring = re.sub(ur'([{,])([a-z]\w*):', ur'\1"\2":', datastring)
data = json.loads(datastring)

这为您提供了一个大字典,其中SKU键和带有嵌套dicts的词典作为数据,包括具有p产品代码和e价格的嵌套SKU:

>>> from pprint import pprint
>>> pprint(data['sku864221'])
{u'deliveryTime': u'Lieferbar innerhalb 48 Stunden',
 u'image': u'/images/m707491_300465.jpg',
 u'name': u'BlackBerry Bold 9900',
 u'sku1104261': {u'e': u'169.90', u'p': u'prod974431'},
 u'sku1444275': {u'e': u'129.90', u'p': u'prod974431'},
 u'sku1444283': {u'e': u'89.90', u'p': u'prod974431'},
 u'sku1444286': {u'e': u'49.90', u'p': u'prod974431'},
 u'sku1444291': {u'e': u'49.90', u'p': u'prod974431'}}