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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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等语言动态生成页面信息。

网页抓取具有动态 javascript 内容的网站

【中文标题】网页抓取具有动态 javascript 内容的网站【英文标题】:Web scraping a website with dynamic javascript content 【发布时间】:2014-05-08 01:04:51 【问题描述】:

所以我使用 python 和 beautifulsoup4(我没有绑定)来抓取网站。问题是当我使用 urllib 获取页面的 html 时,它不是整个页面,因为其中一些是通过 javascript 生成的。有没有办法解决这个问题?

【问题讨论】:

Tried Python BeautifulSoup and Phantom JS: STILL can't scrape websites 的可能重复项 【参考方案1】:

基本上有两个主要选择:

使用浏览器开发工具,看看哪些ajax请求将加载页面并在你的脚本中模拟它们,你可能需要使用json模块将响应json字符串加载到python数据结构中 使用像selenium 这样的工具来打开一个真正的浏览器。浏览器也可以“无头”,见Headless Selenium Testing with Python and PhantomJS

第一个选项更难实现,一般来说更脆弱,但它不需要真正的浏览器并且速度更快。

第二个选项更好,因为您可以获得任何其他真实用户所获得的内容,并且您不必担心页面是如何加载的。 Selenium 在页面上的locating elements 中非常强大——你可能根本不需要BeautifulSoup。但是,无论如何,这个选项比第一个慢。

希望对您有所帮助。

【讨论】:

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

如何使用 node.js 抓取具有动态内容的页面?

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

怎么爬取网页的动态内容,很多都是js动态生

Python的requests包在抓取页面的时候页面源代码抓取不完全,页面数据不是动态加载的。

java爬虫怎么抓取js动态生成的内容

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