如何抓取网页中的动态数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何抓取网页中的动态数据相关的知识,希望对你有一定的参考价值。

首先明确我指的动态数据是什么。
名词定义:动态数据在这里指的是网页中由javascript动态生成的页面内容,即网页源文件中没有,在页面加载到浏览器后动态生成的。
下面进入正题。
抓取静态页面很简单,通过Java获取到html源码,然后分析源码即可得到想要的信息。如获取中国天气网中杭州的天气,只需要找到对应的html页面(http://www.weather.com.cn/weather/101210101.shtml)。
假设我需要输入城市名称获取改城市的天气,数据源还是采用中国天气网。首先要做的是根据城市找到对应的页面。通过简单分析发现,城市与页面的URL有对应,如杭州对应101210101,所以程序的关键就是找到城市与页面的对应关系。
发现该网站的搜索框有中国大多数城市的链接,可以得到城市与_id的对应关系。找到突破口,开始行动。进入首页,查看其源代码,找到搜索框所在位置。
原来数据是通过Javascript动态加进去的,用Chrome的inspect element看到以下内容。
目前可以做的是利用Chrome将html复制到文件,然后解析该文件得到城市与URL的关系。问题是万一网站的城市与URL对应关系有变化,这就很被动还需改程序。
现在的问题是如何用Java获取Javascript动态生成的html内容,不知大家有什么看法。
参考技术A 动态数据采集是一项具有一定挑战性的工作,因此需要运用适当的方法来执行它,您可以使用如Scrapy、BeautifulSoup、lxml、selenium等框架,或者也可以借助爬虫API等解决方案,辅助您爬取和解析动态数据。

python 如何抓取动态页面内容?

我找过用webkit pyQt spynner 和 ghost的,具体怎么操作?
我想封装成一个输入url然后得到最后html的功能

输入url,得到html,我早就写了函数了

自己搜:

getUrlRespHtml

就可以找到对应的python函数:


#------------------------------------------------------------------------------
def getUrlResponse(url, postDict=, headerDict=, timeout=0, useGzip=False, postDataDelimiter="&") :
    """Get response from url, support optional postDict,headerDict,timeout,useGzip

    Note:
    1. if postDict not null, url request auto become to POST instead of default GET
    2  if you want to auto handle cookies, should call initAutoHandleCookies() before use this function.
       then following urllib2.Request will auto handle cookies
    """

    # makesure url is string, not unicode, otherwise urllib2.urlopen will error
    url = str(url);

    if (postDict) :
        if(postDataDelimiter=="&"):
            postData = urllib.urlencode(postDict);
        else:
            postData = "";
            for eachKey in postDict.keys() :
                postData += str(eachKey) + "="  + str(postDict[eachKey]) + postDataDelimiter;
        postData = postData.strip();
        logging.info("postData=%s", postData);
        req = urllib2.Request(url, postData);
        logging.info("req=%s", req);
        req.add_header('Content-Type', "application/x-www-form-urlencoded");
    else :
        req = urllib2.Request(url);

    defHeaderDict = 
        'User-Agent'    : gConst['UserAgent'],
        'Cache-Control' : 'no-cache',
        'Accept'        : '*/*',
        'Connection'    : 'Keep-Alive',
    ;

    # add default headers firstly
    for eachDefHd in defHeaderDict.keys() :
        #print "add default header: %s=%s"%(eachDefHd,defHeaderDict[eachDefHd]);
        req.add_header(eachDefHd, defHeaderDict[eachDefHd]);

    if(useGzip) :
        #print "use gzip for",url;
        req.add_header('Accept-Encoding', 'gzip, deflate');

    # add customized header later -> allow overwrite default header 
    if(headerDict) :
        #print "added header:",headerDict;
        for key in headerDict.keys() :
            req.add_header(key, headerDict[key]);

    if(timeout > 0) :
        # set timeout value if necessary
        resp = urllib2.urlopen(req, timeout=timeout);
    else :
        resp = urllib2.urlopen(req);
        
    #update cookies into local file
    if(gVal['cookieUseFile']):
        gVal['cj'].save();
        logging.info("gVal['cj']=%s", gVal['cj']);
    
    return resp;

#------------------------------------------------------------------------------
# get response html==body from url
#def getUrlRespHtml(url, postDict=, headerDict=, timeout=0, useGzip=False) :
def getUrlRespHtml(url, postDict=, headerDict=, timeout=0, useGzip=True, postDataDelimiter="&") :
    resp = getUrlResponse(url, postDict, headerDict, timeout, useGzip, postDataDelimiter);
    respHtml = resp.read();
    
    #here, maybe, even if not send Accept-Encoding: gzip, deflate
    #but still response gzip or deflate, so directly do undecompress
    #if(useGzip) :
    
    #print "---before unzip, len(respHtml)=",len(respHtml);
    respInfo = resp.info();
    
    # Server: nginx/1.0.8
    # Date: Sun, 08 Apr 2012 12:30:35 GMT
    # Content-Type: text/html
    # Transfer-Encoding: chunked
    # Connection: close
    # Vary: Accept-Encoding
    # ...
    # Content-Encoding: gzip
    
    # sometime, the request use gzip,deflate, but actually returned is un-gzip html
    # -> response info not include above "Content-Encoding: gzip"
    # eg: http://blog.sina.com.cn/s/comment_730793bf010144j7_3.html
    # -> so here only decode when it is indeed is gziped data
    
    #Content-Encoding: deflate
    if("Content-Encoding" in respInfo):
        if("gzip" == respInfo['Content-Encoding']):
            respHtml = zlib.decompress(respHtml, 16+zlib.MAX_WBITS);
        elif("deflate" == respInfo['Content-Encoding']):
            respHtml = zlib.decompress(respHtml, -zlib.MAX_WBITS);

    return respHtml;

及示例代码:

url = "http://www.crifan.com";
respHtml = getUrlRespHtml(url);

完全库函数,自己搜:

crifanLib.py


关于抓取动态页面,详见:

Python专题教程:抓取网站,模拟登陆,抓取动态网页


(自己搜标题即可找到)

追问

这个基本能有,但是我对前台不是很了解。有些url 还是会返回没有执行的js,是因为他js的触发时机的问题吗?

追答

“有些url 还是会返回没有执行的js”
访问某个url,只会返回对应的内容,比如
xxx.js返回是js的源码。
如果想要“执行后的js”,那是需要你自己去模拟的。

参考技术A 下面开始说一下本文抓取动态页面数据的相关工具和库:
1. python 2.7
2. pyqt

3. spynner (在安装过程中,其他的一些依赖库也会自动上网下载安装)
4. BeautifulSoup
5. ide工具是pycharm(当然这个只是个人喜好,也可以使用其他的ide工具)

以上几个工具都可以百度找到,python现在出了3.x版本的,但是由于众多第三方库或架构都没有兼容,并且后续要使用到的爬虫框架scrapy也是没有支持3.x版本,因此还是建议使用2.7版本吧。
spynner和BeautifulSoup下载后,都可以cd到解压出来的目录,然后使用python setup.py install来完成安装,需要注意的是spynner依赖pyqt,所以一定要安装pyqt,否则无法使用spynner。

下面使用一个具体是例子来说明一下spynner和BeautifulSoup的使用,我们就以爬取京东页面上的一些产品数据来说明如何爬取动态页面数据(当然,如果我们过于频繁的爬京东,估计还是有可能被京东将我们ip拉黑的)。
参考技术B 1.先了解网页抓取的逻辑过程

可参考:

【整理】关于抓取网页,分析网页内容,模拟登陆网站的逻辑/流程和注意事项

2.再 利用工具分析出需要的内容 是如何产生的

【总结】浏览器中的开发人员工具(IE9的F12和Chrome的Ctrl+Shift+I)-网页分析的利器

用你所说的Firefox的firebug也可以,但是我用过了,觉得还是没有IE9的F12好用。

3.都分析出来了,找到具体哪个url产生的你所需要的数据了

然后才是用python实现对应的代码。
参考技术C 以前我做过一个。使用pyqt中的webkit,其中有一个功能,可以将html读出来。不记得哪个了。你查一下pyqt库中webkit部分就可以找到。接口不是很多。可能需要等一下。加载一个网页后,检查内容是否完成了,再保存。印象中有几个完成标志,有些可能并不可靠。

以前似乎把它做成了多进程的一个爬行器。的确可以抓到一些动态页面。

webkit内部的一些事情,比如鼠标,键盘事件也有专门的接口。可以发过去,相当于点击,登陆也可以实现。

效率比直接爬行当然要低很多。不过还行。支持js, 支持cookie,支持缓存。

好象还可以轻松就把子链接取出来。
参考技术D 很早之前,学习Python web编程的时候,就涉及一个Python的urllib。可以用urllib.urlopen("url").read()可以轻松读取页面上面的静态信息。但是,随着时代的发展,也来越多的网页中更多的使用javascript、jQuery、PHP等语言动态生成页面信息。

以上是关于如何抓取网页中的动态数据的主要内容,如果未能解决你的问题,请参考以下文章

python 如何抓取动态页面内容?

如何通过 Python 抓取动态网页

如何实时抓取动态网页数据?

python网络爬虫抓取动态网页并将数据存入数据库MySQL

爬虫--python3.6+selenium+BeautifulSoup实现动态网页的数据抓取,适用于对抓取频率不高的情况

爬虫---selenium动态网页数据抓取