如何使用Python抓取动态生成的URL页面?

时间:2014-04-25 20:44:48

标签: python web-scraping beautifulsoup urllib2

我正在努力抓取http://www.dailyfinance.com/quote/NYSE/international-business-machines/IBM/financial-ratios,但是传统的网址字符串构建技术并不起作用,因为"完整的公司名称是插入路径中的&#34 ;串。确切的"完整的公司名称"事先并不知道。只有公司标志," IBM"众所周知。

基本上,我刮擦的方式是循环遍历公司符号数组并在将url字符串发送到urllib2.urlopen(url)之前构建它。但在这种情况下,无法做到。

例如,CSCO字符串是

http://www.dailyfinance.com/quote/NASDAQ/cisco-systems-inc/CSCO/financial-ratios

另一个示例url字符串是AAPL:

http://www.dailyfinance.com/quote/NASDAQ/apple/AAPL/financial-ratios

因此,为了获取网址,我必须在主页的输入框中搜索符号:

http://www.dailyfinance.com/

我注意到当我输入" CSCO"并在Firefox Web开发人员网络选项卡中的{http://www.dailyfinance.com/quote/NASDAQ/apple/AAPL/financial-ratios处检查搜索输入,我注意到get请求正在发送到

http://j.foolcdn.com/tmf/predictivesearch?callback=_predictiveSearch_csco&term=csco&domain=dailyfinance.com

并且引用者实际上给出了我想要捕获的路径

Host: j.foolcdn.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://www.dailyfinance.com/quote/NASDAQ/cisco-systems-inc/CSCO/financial-ratios?source=itxwebtxt0000007
Connection: keep-alive

很抱歉很长的解释。所以问题是如何在Referer中提取网址?如果那是不可能的,我应该如何处理这个问题?还有另一种方式吗?

我非常感谢你的帮助。

2 个答案:

答案 0 :(得分:25)

我喜欢这个问题。因此,我会给出一个非常彻底的答案。为此,我将使用我最喜欢的Requests库和BeautifulSoup4。如果您真的想使用它,请移植到Mechanize由您决定。请求将为您节省大量的麻烦。


首先,您可能正在寻找POST请求。但是,如果搜索功能直接带到您正在寻找的页面,则通常不需要POST请求。那么我们来检查吧,是吗?

当我登陆基本网址http://www.dailyfinance.com/时,我可以通过Firebug或Chrome的检查工具进行简单的检查,当我在搜索栏上输入CSCO或AAPL并启用“跳转”时,有一个301 Moved Permanently状态代码。这是什么意思?

enter image description here

简单来说,我在某处 转移 。此GET请求的URL如下:

http://www.dailyfinance.com/quote/jump?exchange-input=&ticker-input=CSCO

现在,我们通过使用简单的URL操作测试它是否适用于AAPL。

import requests as rq

apl_tick = "AAPL"
url = "http://www.dailyfinance.com/quote/jump?exchange-input=&ticker-input="
r = rq.get(url + apl_tick)
print r.url

以上结果如下:

http://www.dailyfinance.com/quote/nasdaq/apple/aapl
[Finished in 2.3s]

查看响应的网址如何更改?让我们通过将以下内容附加到上面的代码来查找/financial-ratios页面,进一步采用URL操作:

new_url = r.url + "/financial-ratios"
p = rq.get(new_url)
print p.url

运行时,这给出了以下结果:

http://www.dailyfinance.com/quote/nasdaq/apple/aapl
http://www.dailyfinance.com/quote/nasdaq/apple/aapl/financial-ratios
[Finished in 6.0s]

现在我们走在正确的轨道上。我现在将尝试使用BeautifulSoup解析数据。我的完整代码如下:

from bs4 import BeautifulSoup as bsoup
import requests as rq

apl_tick = "AAPL"
url = "http://www.dailyfinance.com/quote/jump?exchange-input=&ticker-input="
r = rq.get(url + apl_tick)
new_url = r.url + "/financial-ratios"
p = rq.get(new_url)

soup = bsoup(p.content)
div = soup.find("div", id="clear").table
rows = table.find_all("tr")
for row in rows:
    print row

然后我尝试运行此代码,只是遇到以下回溯的错误:

  File "C:\Users\nanashi\Desktop\test.py", line 13, in <module>
    div = soup.find("div", id="clear").table
AttributeError: 'NoneType' object has no attribute 'table'

值得注意的是'NoneType' object...行。这意味着我们的目标div不存在! Egads,但为什么我看到以下内容?!

enter image description here

只能有一个解释:表是动态加载的!大鼠。让我们看看我们是否可以找到该表的另一个来源。我研究页面,看到底部有滚动条。这可能意味着表格已加载到框架内,或者直接从其他来源加载并放入页面中的div

我刷新页面并再次观看GET请求。宾果,我发现了一些似乎有点看好的东西:

enter image description here

第三方来源网址,看起来很容易使用自动收报机代码进行操作!让我们尝试将其加载到新标签中。这是我们得到的:

enter image description here

WOW!我们现在拥有非常确切的数据来源。最后一个障碍是当我们尝试使用这个字符串拉出CSCO数据时它会工作(记得我们去了CSCO - &gt; AAPL,现在再次回到CSCO,所以你不会感到困惑)。让我们清理字符串并完全抛弃www.dailyfinance.com的角色。我们的新网址如下:

http://www.motleyfool.idmanagedsolutions.com/stocks/financial_ratios.idms?SYMBOL_US=AAPL

让我们在最后的刮刀中尝试使用它!

from bs4 import BeautifulSoup as bsoup
import requests as rq

csco_tick = "CSCO"
url = "http://www.motleyfool.idmanagedsolutions.com/stocks/financial_ratios.idms?SYMBOL_US="
new_url = url + csco_tick

r = rq.get(new_url)
soup = bsoup(r.content)

table = soup.find("div", id="clear").table
rows = table.find_all("tr")
for row in rows:
    print row.get_text()

我们对CSCO财务比率数据的原始结果如下:

Company
Industry


Valuation Ratios


P/E Ratio (TTM)
15.40
14.80


P/E High - Last 5 Yrs 
24.00
28.90


P/E Low - Last 5 Yrs
8.40
12.10


Beta
1.37
1.50


Price to Sales (TTM)
2.51
2.59


Price to Book (MRQ)
2.14
2.17


Price to Tangible Book (MRQ)
4.25
3.83


Price to Cash Flow (TTM)
11.40
11.60


Price to Free Cash Flow (TTM)
28.20
60.20


Dividends


Dividend Yield (%)
3.30
2.50


Dividend Yield - 5 Yr Avg (%)
N.A.
1.20


Dividend 5 Yr Growth Rate (%)
N.A.
144.07


Payout Ratio (TTM)
45.00
32.00


Sales (MRQ) vs Qtr 1 Yr Ago (%)
-7.80
-3.70


Sales (TTM) vs TTM 1 Yr Ago (%)
5.50
5.60


Growth Rates (%)


Sales - 5 Yr Growth Rate (%)
5.51
5.12


EPS (MRQ) vs Qtr 1 Yr Ago (%)
-54.50
-51.90


EPS (TTM) vs TTM 1 Yr Ago (%)
-54.50
-51.90


EPS - 5 Yr Growth Rate (%)
8.91
9.04


Capital Spending - 5 Yr Growth Rate (%)
20.30
20.94


Financial Strength


Quick Ratio (MRQ)
2.40
2.70


Current Ratio (MRQ)
2.60
2.90


LT Debt to Equity (MRQ)
0.22
0.20


Total Debt to Equity (MRQ)
0.31
0.25


Interest Coverage (TTM)
18.90
19.10


Profitability Ratios (%)


Gross Margin (TTM)
63.20
62.50


Gross Margin - 5 Yr Avg
66.30
64.00


EBITD Margin (TTM)
26.20
25.00


EBITD - 5 Yr Avg
28.82
0.00


Pre-Tax Margin (TTM)
21.10
20.00


Pre-Tax Margin - 5 Yr Avg
21.60
18.80


Management Effectiveness (%)


Net Profit Margin (TTM)
17.10
17.65


Net Profit Margin - 5 Yr Avg
17.90
15.40


Return on Assets (TTM)
8.30
8.90


Return on Assets - 5 Yr Avg
8.90
8.00


Return on Investment (TTM)
11.90
12.30


Return on Investment - 5 Yr Avg
12.50
10.90


Efficiency


Revenue/Employee (TTM)
637,890.00
556,027.00


Net Income/Employee (TTM)
108,902.00
98,118.00


Receivable Turnover (TTM)
5.70
5.80


Inventory Turnover (TTM)
11.30
9.70


Asset Turnover (TTM)
0.50
0.50

[Finished in 2.0s]

清理数据取决于您。


从这次刮擦中学到的一个好教训并不是所有数据都只包含在一个页面中。很高兴看到它来自另一个静态网站。如果它是通过JavaScript或AJAX调用等生成的,我们的方法可能会遇到一些困难。

希望你从中学到了一些东西。如果这有帮助并祝你好运,请告诉我们。

答案 1 :(得分:2)

不回答您的具体问题,但解决了您的问题。

http://www.dailyfinance.com/quotes/{Company Symbol}/{Stock Exchange}

示例:

http://www.dailyfinance.com/quotes/AAPL/NAS

http://www.dailyfinance.com/quotes/IBM/NYSE

http://www.dailyfinance.com/quotes/CSCO/NAS

要进入财务比率页面,您可以使用以下内容:

import urllib2

def financial_ratio_url(symbol, stock_exchange):
    starturl  = 'http://www.dailyfinance.com/quotes/'
    starturl += '/'.join([symbol, stock_exchange])
    req = urllib2.Request(starturl)
    res = urllib2.urlopen(starturl)
    return '/'.join([res.geturl(),'financial-ratios'])

示例:

financial_ratio_url('AAPL', 'NAS')
'http://www.dailyfinance.com/quote/nasdaq/apple/aapl/financial-ratios'