- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试从 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 生成数据表。有一些替代方案,例如 scrapyjs或 splash这允许获取 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/
我正在使用 Gunicorn 为 Django 应用程序提供服务,它工作正常,直到我将其超时时间从 30 秒更改为 900000 秒,我不得不这样做,因为我有一个用例需要上传和处理一个巨大的文件(过程
我有一个带有非常基本的管道的Jenkinsfile,它可以旋转docker容器: pipeline { agent { dockerfile { args '-u root' } } stag
在学习 MEAN 堆栈的过程中,我遇到了一个问题。每当我尝试使用 Passport 验证方法时,它都不会返回任何响应。我总是收到“localhost没有发送任何数据。ERR_EMPTY_RESPONS
在当今的大多数企业堆栈中,数据库是我们存储所有秘密的地方。它是安全屋,是待命室,也是用于存储可能非常私密或极具价值的物品的集散地。对于依赖它的数据库管理员、程序员和DevOps团队来说,保护它免受所
是否可以创建像图片上那样的边框?只需使用 css 边框属性。最终结果将是没 Angular 盒子。我不想添加额外的 html 元素。我只想为每个 li 元素添加 css 边框信息。 假设这是一个 ul
我是一名优秀的程序员,十分优秀!