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

标签 python web-scraping beautifulsoup urllib2

我正在尝试抓取 http://www.dailyfinance.com/quote/NYSE/international-business-machines/IBM/financial-ratios ,但传统的 url 字符串构建技术不起作用,因为“完整的公司名称被插入到路径中”字符串。并且事先不知道确切的“公司全名”。只有公司标志“IBM”为人所知。

基本上,我抓取的方式是循环遍历公司符号数组并在将其发送到 urllib2.urlopen(url) 之前构建 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

所以为了得到url,我只好在主页的输入框中搜索符号:

http://www.dailyfinance.com/

我注意到,当我键入“CSCO”并在 Firefox Web 开发人员网络选项卡中检查位于(http://www.dailyfinance.com/quote/NASDAQ/apple/AAPL/financial-ratios 处的搜索输入时,我注意到获取请求正在发送到

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

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

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中的url?如果那不可能,我应该如何解决这个问题?还有别的办法吗?

非常感谢您的帮助。

最佳答案

我喜欢这个问题。因此,我会给出一个非常彻底的答案。为此,我将使用我最喜欢的 Requests 库和 BeautifulSoup4。如果您真的想使用它,则移植到 Mechanize 取决于您。不过,请求会让你省去很多麻烦。


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

当我登陆基本 URL 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]

看看响应的 URL 是如何变化的?让我们通过将以下内容附加到上面的代码来查找 /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 不存在!哎呀,但为什么我会看到以下内容?!

enter image description here

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

我刷新页面并再次查看 GET 请求。宾果游戏,我发现了一些看起来很有希望的东西:

enter image description here

第三方源 URL,看,使用股票代码可以轻松操纵它!让我们尝试将其加载到新选项卡中。这是我们得到的:

enter image description here

哇!我们现在有了非常准确的数据来源。最后一个障碍是,当我们尝试使用此字符串提取 CSCO 数据时它是否有效(请记住我们去了 CSCO -> 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 调用等生成的,我们的方法可能会遇到一些困难。

希望你能从中学到一些东西。让我们知道这是否有帮助,祝您好运。

关于python - 如何使用 Python 抓取具有动态生成的 URL 的页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23302676/

相关文章:

Python 2.7 : ValueError using csv to create a dictionary

javascript - 获取 Json 文件时出错

perl - 为什么 Web::Scraper 不解析 script-tag?

python - "ImportError: no suitable image found"使用 BeautifulSoup 和 Python3.8

Python Web Scraping 表返回 None

python - 为什么我的 index.html 不能连接到我的 index.css 文件?

python - 最小化带有 2 个参数的函数

python - 采纳文件

javascript - 在 Puppeteer 请求拦截期间手动更改响应 URL

Python-是否有一个模块可以自动从网页上抓取文章的内容?