gpt4 book ai didi

python - Scrapy hxs.select() 没有选择所有结果

转载 作者:太空狗 更新时间:2023-10-30 02:32:14 25 4
gpt4 key购买 nike

我正在尝试从 here 中获取赔率.

目前只是尝试使用以下蜘蛛记录结果:

def parse(self, response):         
log.start("LogFile.txt", log.DEBUG);

hxs = HtmlXPathSelector(response)
sites = hxs.select('//div[@class="fb_day_type_wrapper"]')

items = []
for site in sites:
siteAddress = urlparse.urljoin(response.url, site.extract())
self.log('Found category url: %s' % siteAddress)

这只会记录条目:这个市场目前不可用....不是包含赔率的其他元素。

我尝试了几种不同的选择器,但都没有成功。看起来一旦我尝试进入元素 div[@class="fb_day_type_wrapper"] 我就什么也得不到返回。我使用 scrapy shell 得到了相同的结果。

最佳答案

该站点使用javascript 生成数据表。有一些替代方案,例如 scrapyjssplash这允许获取 js 呈现的 html 页面。如果您只需要抓取一页,使用 Selenium 可能会更好。

否则,您可能需要进入硬核模式并使用数据对站点中正在发生的事情进行逆向工程。我将向您展示如何做到这一点。

首先,启动 scrapy shell这样我们就可以浏览网页了:

scrapy shell http://www.paddypower.com/football/football-matches/premier-league

注意:我使用的是 python 2.7.4、ipython 0.13.2 和 scrapy 0.18.0。

如果您在浏览器中查找“Crystal Palace v Fulham”的源代码,您会看到有一个包含该引用的 javascript 代码。 <script> block 看起来像:

document.bodyOnLoad.push(function() {
lb_fb_cpn_init(
"",
"html",
"MR_224",
{category: 'SOCCER',

我们在 shell 中查找这个元素:

In [1]: hxs.select('//script[contains(., "lb_fb_cpn_init")]')
Out[1]: [<HtmlXPathSelector xpath='//script[contains(., "lb_fb_cpn_init")]' data=u'<script type="text/javascript">\n/* $Id: '>]

如果您查找 lb_fb_cpn_init参数,您将看到我们正在寻找的数据以这种形式作为参数传递:

[{names: {en: 'Newcastle v Liverpool'}, ...

事实上有这样三个论点:

In [2]: hxs.select('//script[contains(., "lb_fb_cpn_init")]').re('\[{names:')
Out[2]: [u'[{names:', u'[{names:', u'[{names:']

所以我们提取所有这些,注意我们使用了很多正则表达式:

In [3]: js_args = hxs.select('//script[contains(., "lb_fb_cpn_init")]').re(r'(\[{names:(?:.+?)\]),')

In [4]: len(js_args)
Out[4]: 3

这里的想法是我们要将 javascript 代码(这是一个文字对象)解析为 python 代码(一个 dict)。我们可以使用 json.loads但要这样做,js 代码必须是有效的 json 对象,即字段名称和字符串包含在 "" 中。 .

我们继续这样做。首先,我将参数作为 javascript 列表加入到单个字符串中:

In [5]: args_raw = '[{}]'.format(', '.join(js_args))

然后我们将字段名称包含在""用双引号替换单引号:

In [6]: import re

In [7]: args_json = re.sub(r'(,\s?|{)(\w+):', r'\1"\2":', args_raw).replace("'", '"')

这可能并不总是适用于所有情况,因为 javascript 代码可能具有不容易用单个 re.sub 替换的模式。和/或 .replace .

我们准备将 javascript 代码解析为 json 对象:

In [8]: import json

In [9]: data = json.loads(args_json)

In [10]: len(data)
Out[10]: 3

在这里,我只是在寻找赛事名称和赔率。你可以看看data内容以查看它的外观。

幸运的是,数据似乎具有相关性:

In [11]: map(len, data)
Out[11]: [20, 20, 60]

您也可以构建一个 dict通过使用 ev_id 来自他们三个 field 。我将假设 data[0]data[1]data[2]有直接关系每个事件包含 3 个项目。这可以通过以下方式轻松验证:

In [12]: map(lambda v: v['ev_id'], data[2])
Out [12]:
[5889932,
5889932,
5889932,
5889933,
5889933,
5889933,
...

通过一些 python-fu,我们可以合并记录:

In [13]: odds = iter(data[2])

In [14]: odds_merged = zip(odds, odds, odds)

In [15]: data_merged = zip(data[0], data[1], odds_merged)

In [16]: len(data_merged)
Out[16]: 20

最后,我们收集数据:

In [17]: get_odd = lambda obj: (obj['names']['en'], '/'.join([obj['lp_num'], obj['lp_den']]))

In [18]: event_odds = []

In [19]: for event, _, odds in data_merged:
....: event_odds.append({'name': event['names']['en'], 'odds': dict(map(get_odd, odds)), 'url': event['url']})
....:

In [20]: event_odds
Out[20]:
[{'name': u'Newcastle v Liverpool',
'odds': {u'Draw': u'14/5', u'Liverpool': u'17/20', u'Newcastle': u'3/1'},
'url': u'http://www.paddypower.com/football/football-matches/premier-league-matches/Newcastle%2dv%2dLiverpool-5889932.html'},
{'name': u'Arsenal v Norwich',
'odds': {u'Arsenal': u'3/10', u'Draw': u'9/2', u'Norwich': u'9/1'},
'url': u'http://www.paddypower.com/football/football-matches/premier-league-matches/Arsenal%2dv%2dNorwich-5889933.html'},
{'name': u'Chelsea v Cardiff',
'odds': {u'Cardiff': u'10/1', u'Chelsea': u'1/4', u'Draw': u'5/1'},
'url': u'http://www.paddypower.com/football/football-matches/premier-league-matches/Chelsea%2dv%2dCardiff-5889934.html'},
{'name': u'Everton v Hull',
'odds': {u'Draw': u'10/3', u'Everton': u'4/9', u'Hull': u'13/2'},
'url': u'http://www.paddypower.com/football/football-matches/premier-league-matches/Everton%2dv%2dHull-5889935.html'},
{'name': u'Man Utd v Southampton',
'odds': {u'Draw': u'3/1', u'Man Utd': u'8/15', u'Southampton': u'11/2'},
'url': u'http://www.paddypower.com/football/football-matches/premier-league-matches/Man%2dUtd%2dv%2dSouthampton-5889939.html'},
...

如您所见,网络抓取非常具有挑战性(而且很有趣!)。这完全取决于网站如何显示数据。在这里你可以通过使用 Selenium 来节省时间,但是如果你想抓取一个大型网站,与 Scrapy 相比,Selenium 会非常慢。

另外还要考虑站点是否会经常获取代码更新,那样的话你会花更多的时间逆向工程js代码。在那种情况下,像 scrapyjs 这样的解决方案或 splash可能是更好的选择。

最后的评论:

  • 现在您拥有了提取数据所需的所有代码。您需要将其集成到您的蜘蛛回调中并构建您的项目。
  • 不要使用 log.start .使用设置 LOG_FILE (命令行参数:--set LOG_FILE=mylog.txt)。
  • 记住 .extract()总是返回一个列表。

关于python - Scrapy hxs.select() 没有选择所有结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19433961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com