我试图开发一个简单的网页刮板。我想提取没有HTML代码的文本。它适用于普通HTML,但不适用于JavaScript代码添加文本的某些页面。
例如,如果一些JavaScript代码添加了一些文本,我不能看到它,因为当我调用:
response = urllib2.urlopen(request)
我得到了原始文本而没有添加的文本(因为JavaScript是在客户端执行的)。
所以,我正在寻找一些解决这个问题的想法。
我试图开发一个简单的网页刮板。我想提取没有HTML代码的文本。它适用于普通HTML,但不适用于JavaScript代码添加文本的某些页面。
例如,如果一些JavaScript代码添加了一些文本,我不能看到它,因为当我调用:
response = urllib2.urlopen(request)
我得到了原始文本而没有添加的文本(因为JavaScript是在客户端执行的)。
所以,我正在寻找一些解决这个问题的想法。
当前回答
EDIT 2021年9月:phantomjs也不再维护
EDIT 30/Dec/2017:这个答案出现在谷歌搜索的顶部结果中,所以我决定更新它。老答案仍然在最后。
dryscape不再维护,开发人员推荐的库dryscape仅适用于Python 2。我发现使用Selenium的python库和Phantom JS作为web驱动程序足够快,也很容易完成工作。
一旦你安装了Phantom JS,确保phantomjs二进制文件在当前路径下可用:
phantomjs --version
# result:
2.1.1
#例子 为了给出一个例子,我用下面的HTML代码创建了一个示例页面。(链接):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Javascript scraping test</title>
</head>
<body>
<p id='intro-text'>No javascript support</p>
<script>
document.getElementById('intro-text').innerHTML = 'Yay! Supports javascript';
</script>
</body>
</html>
没有javascript,它说:不支持javascript和javascript:耶!支持javascript
#抓取没有JS支持:
import requests
from bs4 import BeautifulSoup
response = requests.get(my_url)
soup = BeautifulSoup(response.text)
soup.find(id="intro-text")
# Result:
<p id="intro-text">No javascript support</p>
#抓取与JS支持:
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.get(my_url)
p_element = driver.find_element_by_id(id_='intro-text')
print(p_element.text)
# result:
'Yay! Supports javascript'
你也可以使用Python库dryscraping来抓取javascript驱动的网站。
#抓取与JS支持:
import dryscrape
from bs4 import BeautifulSoup
session = dryscrape.Session()
session.visit(my_url)
response = session.body()
soup = BeautifulSoup(response)
soup.find(id="intro-text")
# Result:
<p id="intro-text">Yay! Supports javascript</p>
其他回答
把BeautifulSoup和Selenium混合在一起对我来说效果很好。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup as bs
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))) #waits 10 seconds until element is located. Can have other wait conditions such as visibility_of_element_located or text_to_be_present_in_element
html = driver.page_source
soup = bs(html, "lxml")
dynamic_text = soup.find_all("p", {"class":"class_name"}) #or other attributes, optional
else:
print("Couldnt locate element")
附注:你可以在这里找到更多的等待条件
如前所述,Selenium是呈现JavaScript结果的好选择:
from selenium.webdriver import Firefox
from selenium.webdriver.firefox.options import Options
options = Options()
options.headless = True
browser = Firefox(executable_path="/usr/local/bin/geckodriver", options=options)
url = "https://www.example.com"
browser.get(url)
gazpacho是一个非常容易解析渲染html的库:
from gazpacho import Soup
soup = Soup(browser.page_source)
soup.find("a").attrs['href']
听起来好像你真正要找的数据可以通过主页面上的一些javascript调用的辅助URL访问。
虽然您可以尝试在服务器上运行javascript来处理这个问题,但一种更简单的方法可能是使用Firefox加载页面,并使用Charles或Firebug之类的工具来准确识别辅助URL。然后,您可以直接查询该URL以获得您感兴趣的数据。
EDIT 2021年9月:phantomjs也不再维护
EDIT 30/Dec/2017:这个答案出现在谷歌搜索的顶部结果中,所以我决定更新它。老答案仍然在最后。
dryscape不再维护,开发人员推荐的库dryscape仅适用于Python 2。我发现使用Selenium的python库和Phantom JS作为web驱动程序足够快,也很容易完成工作。
一旦你安装了Phantom JS,确保phantomjs二进制文件在当前路径下可用:
phantomjs --version
# result:
2.1.1
#例子 为了给出一个例子,我用下面的HTML代码创建了一个示例页面。(链接):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Javascript scraping test</title>
</head>
<body>
<p id='intro-text'>No javascript support</p>
<script>
document.getElementById('intro-text').innerHTML = 'Yay! Supports javascript';
</script>
</body>
</html>
没有javascript,它说:不支持javascript和javascript:耶!支持javascript
#抓取没有JS支持:
import requests
from bs4 import BeautifulSoup
response = requests.get(my_url)
soup = BeautifulSoup(response.text)
soup.find(id="intro-text")
# Result:
<p id="intro-text">No javascript support</p>
#抓取与JS支持:
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.get(my_url)
p_element = driver.find_element_by_id(id_='intro-text')
print(p_element.text)
# result:
'Yay! Supports javascript'
你也可以使用Python库dryscraping来抓取javascript驱动的网站。
#抓取与JS支持:
import dryscrape
from bs4 import BeautifulSoup
session = dryscrape.Session()
session.visit(my_url)
response = session.body()
soup = BeautifulSoup(response)
soup.find(id="intro-text")
# Result:
<p id="intro-text">Yay! Supports javascript</p>
这似乎是一个很好的解决方案,从一个伟大的博客文章
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtWebKit import *
from lxml import html
#Take this class for granted.Just use result of rendering.
class Render(QWebPage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebPage.__init__(self)
self.loadFinished.connect(self._loadFinished)
self.mainFrame().load(QUrl(url))
self.app.exec_()
def _loadFinished(self, result):
self.frame = self.mainFrame()
self.app.quit()
url = 'http://pycoders.com/archive/'
r = Render(url)
result = r.frame.toHtml()
# This step is important.Converting QString to Ascii for lxml to process
# The following returns an lxml element tree
archive_links = html.fromstring(str(result.toAscii()))
print archive_links
# The following returns an array containing the URLs
raw_links = archive_links.xpath('//div[@class="campaign"]/a/@href')
print raw_links