V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
LINAICAI
V2EX  ›  问与答

python 爬虫问题

  •  
  •   LINAICAI · 2014-12-25 09:46:36 +08:00 · 3353 次点击
    这是一个创建于 3632 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想爬一个网站,发现用了函数翻页,地址URL不变,怎样爬?
    (function(){

    var loadImageOnScroll=_.throttle(function(){
        var bodyScrollTop = $("body").scrollTop() || $(window).scrollTop()
        var windowHeight = $(window).height();
        $("div.thumbnail img").each(function(){
            var $this = $(this)
            if(!$this.attr("src") && $this.offset().top<bodyScrollTop+windowHeight){
                $this.attr("src",$this.attr("data-src"));
                $this[0].onload=function(){
                    $this.css("min-height","0")
                }
            }
        });
    },200)
    
    function domReady(){
        initPagenation();
        initSelectPic();
        initStar();
        ajax_get_star_info()
        if(!_u.isMobile()){
            setTimeout(showBigImgIfUrlIndicate,500)
        }
        $(window).scroll(loadImageOnScroll)
    }
    
    function showBigImgIfUrlIndicate(){
        var showbig=url_param("showbig")
        if(showbig=="last" || showbig=="next"){
            var imgs=$("div.thumbnail img");
            if(imgs.length>0){
                if(showbig=="last"){
                    showBigImg(imgs[imgs.length-1])
                }
                else{
                    showBigImg(imgs[0])
                }
            }
        }
    }
    
    function ajax_get_star_info(){
        var ids=$.map($("div.thumbnail[data-id]"),function(obj,i){
            return $(obj).attr("data-id")
        })
        if(ids.length==0){
            return;
        }
        var url = '/ajax/imgs/like/'+ids.join(",")
        return $.ajax({
            dataType: "json",
            url: url,
            cache:false
        }).done(function(resp){
            if(resp && resp.code==0){
                set_img_stars(resp.likes,resp.user_imgs)
            }
        }).fail(function(){
        });
    }
    
    /**
     *  likes dict {img_id:likecount}
     */
    function set_img_stars(likes,user_imgs){
    
        $("div.thumbnail[data-id]").each(function(x){
            var obj = $(this)
            var id=obj.attr("data-id")
            obj.find("div.bottombar span.starcount").text(likes[id] || 0)
            var star_icon = obj.find("div.bottombar span.star")
            if(user_imgs.indexOf(id)>=0){
                set_img_liked(star_icon)
            }
            else{
                set_img_disliked(star_icon)
            }
        })
    }
    
    //
    function initStar(){
        $("div.thumbnail .bottombar span.star").click(function(){
            var id=$(this).closest("div.thumbnail").find("img").attr("data-id")
            var starClass = $(this).attr("data-star-class") || "icon-star"
            if ($(this).hasClass(starClass+"-empty")){
                like_img_by_id(id,this)
                _hmt.push(['_trackEvent', 'image', 'like', id]);
            }
            else{
                dislike_img_by_id(id,this)
                _hmt.push(['_trackEvent', 'image', 'dislike', id]);
            }
        });
    }
    
    //update,pass
    function set_img_liked(obj,incr){
        var starClass = $(obj).attr("data-star-class") || "icon-star"
        $(obj).removeClass(starClass+"-empty").addClass(starClass)
        if(incr){
            var countobj= $(obj).parent().find("span.starcount")
            var count = countobj.text()
            count = isNaN(parseInt(count))? 0 : parseInt(count)
            countobj.text(count+1)
        }
    }
    
    function set_img_disliked(obj,desc){
        var starClass = $(obj).attr("data-star-class") || "icon-star"
        $(obj).removeClass(starClass).addClass(starClass+"-empty")
        if(desc){
            var countobj= $(obj).parent().find("span.starcount")
            var count = countobj.text()
            count = isNaN(parseInt(count))? 0 : parseInt(count)
            countobj.text(count-1<=0?0:count-1)
        }
    }
    function dislike_img_by_id(id,obj){
        if(!Core.isLogedIn()){
            return Core.gotoLogin(true)
        }
        var url="/ajax/pic/"+id+"/dislike"
        return $.ajax({
            type:"POST",
            dataType: "json",
            url: url,
            cache:false
        }).done(function(resp){
            if(resp){
                if (resp.code==0){
                    set_img_disliked(obj,true)
                    return
                }
                if(resp.code==RESP_CODE.need_login){
                    return Core.gotoLogin(true)
                }
            }
            alert("取消喜欢图片失败")
        }).fail(function(){
            alert("服务器出差中,请等待它归来")
        });
    
    }
    
    //pass
    function like_img_by_id(id,obj,fn){
        if(!Core.isLogedIn()){
            return Core.gotoLogin(true)
        }
        var url="/ajax/pic/"+id+"/like"
        return $.ajax({
            type:"POST",
            dataType: "json",
            url: url,
            //IE9会cache,这里加上一个参数
            cache:false
        }).done(function(resp){
            if(resp){
                if(resp.code==0){
                    if(obj){
                        set_img_liked(obj,true)
                    }
                    if(fn){
                        fn();
                    }
                    return
                }
                else if(resp.code==RESP_CODE.need_login){
                    return Core.gotoLogin(true)
                }
            }
            alert("喜欢图片失败..")
        }).fail(function(){
            alert("服务器出差中,请等待它归来")
        });
    }
    
    function findNextImg(url){
        var a=$("div.thumbnail img");
        for(var i=0;i<a.length;i++){
            if($(a[i]).attr('data-bigimg')==url && i<a.length-1){
                return a[i+1]
            }
        }
    }
    
    function findLastImg(url){
        var a=$("div.thumbnail img");
        for(var i=0;i<a.length;i++){
            if($(a[i]).attr('data-bigimg')==url && i>0){
                return a[i-1]
            }
        }
    }
    
    function goNextPage(){
        var p=getCurrentPage();
        var url=url_param("p",p+1);
        url = url_param("showbig","next",url)
        window.location=url
    }
    
    function goLastPage(){
        var p=getCurrentPage();
        if(p>0){
            var url=url_param("p",p-1);
            url = url_param("showbig","last",url)
            window.location=url
        }
    }
    
    function onDialogOpen(url,topicurl,imgid,dialog){
    
        function goNextPic(k){
            Core.PageAlert.close()
                var obj=findNextImg(url)
                if(obj){
                    $.modal.close();
                    showBigImg(obj)
                }
                else{
                    goNextPage();
                }
            k.preventDefault()
        }
    
        function goPrePic(k){
    
                Core.PageAlert.close()
                var obj=findLastImg(url)
                if(obj){
                    $.modal.close();
                    showBigImg(obj)
                }
                else{
                    goLastPage();
                }
                k.preventDefault()
        }
    
        $("body").keydown(function(k){
            //support tab on textarea
            //方向键向右
            if (k.which== 39) { 
                goNextPic(k);
                return false;
            }
            //方向按键向左
            else if(k.which==37){
                goPrePic(k);
                return false;
            }
            else if(k.which==13){
                //进入帖子详细页
                window.open(topicurl,"_blank");
                return false;
            }
            //空格按键,加收藏
            else if(k.which==32){
                //添加到收藏
                like_img_by_id(imgid,null,function(){
                    //dialog.container.find(" ")
                    Core.PageAlert.success("喜欢图片成功.")
                });
                return false;
            }
        })
    
        $(".big_img_div .prepic").click(function(k){
            goPrePic(k)
        })
    
        $(".big_img_div .nextpic").click(function(k){
            goNextPic(k)
        })
    
        $(".big_img_div img").mousemove(function(k){
            $(".big_img_tips").css("left",k.clientX).css("top",k.clientY);
        })
    
        $(".big_img_div img").one("mouseenter",function(k){
            setTimeout(function(){
                $(".big_img_tips").show().delay(3000).fadeOut()
            },500);
        });
    }
    
    function onDialogClose(url){
        $("body").unbind("keydown");
    }
    
    function showBigImg(obj){
        var url=$(obj).attr("data-bigimg")
        var width=$(obj).attr("data-width")
        var height=$(obj).attr("data-height")
        var topicurl = $(obj).attr("data-url")
        var topictitle= $(obj).attr("data-title")
        var userurl = $(obj).attr("data-userurl")
        var imgid= $(obj).attr("data-id")
        var opt= {
            zIndex: 10000,
            close: true,
            escClose: true,
            height:height,
            width:width,
            opacity: 70,
            containerCss:{"margin-top":"20px"},
            onOpen:function(dialog){
                onDialogOpen(url,topicurl,imgid,dialog);
                dialog.overlay.show();
                dialog.container.show();
                dialog.data.fadeIn('slow')
            },
            onClose:function(dialog){
                $.modal.close(); // must call this!
                onDialogClose(url)
            }
        }
        var fixTop=parseInt(($(window).height()-height)/2-20)
        if(fixTop<0){
            fixTop=0;
        }
        opt=fixPopPosition(opt,fixTop)
    
        var tpl=$("script[data-tpl='view_big_img']").html()
        tpl=new Templet(tpl)
        $(tpl.render({
            url:url,
            width:width,
            height:height,
            topicurl:topicurl,
            topictitle:topictitle
        })).modal(opt)
    
        /*
        $(_u.strformat('<div class="big_img_div"><img src="{0}" style="width:{1}px;height:{2}px" />'+
                    '<p class="text-center" style="margin-top:10px;"><span class="pull-left label label-info" title="点击左方向按键←查看上一张">←</span><a target="_douban" class="label label-success" href="{3}">查看原帖</a><span class="pull-right label label-info" title="点击右方向按键→查看下一张">→</span></p></div>',url,width,height,topicurl,topictitle)).modal(opt);
                    */
        _hmt.push(['_trackEvent', 'image', 'viewbig', '']);
    }
    
    function initSelectPic(){
        var u=location.href
        $(".topcorner").hide()
        //非mobile版本才加这个逻辑
        if(!_u.isMobile()){
            $("div.thumbnail img").click(function(){
                showBigImg(this)
            });
        }
    }
    
    function fixPopPosition(opt,t){
        var obj= opt || {};
        obj.docDem = [$("body").height(),$("body").width()]
        obj.position= [t]
        return obj;
    }
    
    function hidePic(id,obj){
        var url="/ajax/pic/"+id+"/hide"
        return $.ajax({
            type:"POST",
            dataType: "json",
            url: url,
            //IE9会cache,这里加上一个参数
            cache:false
        }).done(function(resp){
            if(resp && resp.code==0){
                $(obj).closest("div.thumbnail").remove()
            }
            else{
                alert("选择为可见出错")
            }
        }).fail(function(){
            alert("设置为可见失败")
        });
    }
    
    function selectPic(id,obj){
        var url="/ajax/pic/"+id+"/select"
        return $.ajax({
            type:"POST",
            dataType: "json",
            url: url,
            //IE9会cache,这里加上一个参数
            cache:false
        }).done(function(resp){
            if(resp && resp.code==0){
                $(obj).closest("div.thumbnail").remove()
            }
            else{
                alert("选择为可见出错")
            }
        }).fail(function(){
            alert("设置为可见失败")
        });
    }
    
    function login(){
    
    }
    
    function regist(){
    
    }
    
    function url_param(name,value,url) {
        //return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
        if(typeof value=="undefined"){
            return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(url || location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
        }
        else{
            url= url || window.location.href;
            name = name.toString();
            value = encodeURIComponent(value.toString())
            var r = new RegExp("(^|\\W)" + name + "=[^&]*", "g");
            var vUrl = url.split("#");
            vUrl[0] = (vUrl[0].match(r)) ? vUrl[0].replace(r, "$1" + name + "=" + value) : vUrl[0] + (vUrl[0].indexOf("?") == -1 ? "?" : "&") + name + "=" + value;
            return vUrl.join("#");
        }
    }
    
    function getCurrentPage(){
        var p = url_param("p")
        p = p || 0
        p = p-0
        return p
    }
    
    function initPagenation(){
        var tpl=$("script[data-tpl='pagination']").html()
        tpl=new Templet(tpl)
        var pcount=cgidata.page_count
        var pages=[]
        var p=getCurrentPage();
        var start= (p-2)<0?0:(p-2);
        var end=p+2>pcount?pcount:p+2;
        for(var i=start;i<end;i++){
            pages.push({url:url_param("p",i),page:i+1,"class":(p==i)?"active":""})
        }
        $('div.pagination ul').html(tpl.render({pages:pages,next:end<pcount}));
        if(p-1>=0){
            $('div.pagination ul a[data-type="pre"]').attr('href',url_param("p",p-1))
        }
        else{
            $('div.pagination ul a[data-type="pre"]').parent().remove();
        }
        if(p+1<pcount){
            $('div.pagination ul a[data-type="next"]').attr('href',url_param("p",p+1))
        }
        else{
            $('div.pagination ul a[data-type="next"]').parent().remove();
        }
    }
    
    Core.domReady(domReady)
    

    })();

    我希望迭代出每一页得数据,当然我爬数据得正则已经准备好了,问题在怎样取得每一页得url?

    22 条回复    2014-12-25 16:15:15 +08:00
    icedx
        1
    icedx  
       2014-12-25 09:50:53 +08:00 via Android   ❤️ 1
    上调试 看翻页时候网页向服务器请求了啥 这种最好爬了 肯定是AJAX 请求的数据
    LINAICAI
        2
    LINAICAI  
    OP
       2014-12-25 09:59:45 +08:00
    @icedx 感谢,已经用调试模式看到下一页得URL了,问题又来了,除了下一页,貌似还有一个机制,就是每一页首次加载只有8行数据,滑动浏览器才会加载剩余得数据,怎么处理
    icedx
        3
    icedx  
       2014-12-25 10:02:02 +08:00 via Android
    @LINAICAI
    继续开着调试 然后把页面拉倒第9 行呗
    jint
        4
    jint  
       2014-12-25 10:12:55 +08:00 via Android
    这是手把手的节奏啊。
    LINAICAI
        5
    LINAICAI  
    OP
       2014-12-25 10:14:23 +08:00
    @icedx 看不到第九行数据的地址了
    调试点->资源 也看不到只有一个参数p代表页数
    icedx
        6
    icedx  
       2014-12-25 10:25:56 +08:00 via Android
    @LINAICAI 那就断网, 然后拉倒第九行, 看看JS 干了什么...
    @jint 我看他头像都没有, 觉得手把手还是需要的...
    invite
        7
    invite  
       2014-12-25 10:30:18 +08:00
    很明显,需要看网络也,看看请求地址就行了。分析JS干嘛。
    LINAICAI
        8
    LINAICAI  
    OP
       2014-12-25 10:51:51 +08:00
    @icedx 新手你懂的,原本是IOS开发,不会web这套。。。
    所以,也是折腾,现在是各种爬数据做app的阶段。
    回归上面的问题,我还是不明白,关于断网看JS干了什么,第一次我不知道怎么看JS干了什么,第二看到JS干了什么就知道加载每一页的全部内容的URL吗
    gamexg
        9
    gamexg  
       2014-12-25 11:19:52 +08:00
    F12 => 网络
    刷新网页,点下一页或往下拉网页,所有的请求一览无余,自己翻。
    icedx
        10
    icedx  
       2014-12-25 11:21:37 +08:00 via Android   ❤️ 1
    @LINAICAI 是啊 你不是说看不到第九行的数据的地址了么
    多半是是第九行有段JS 会在拉到的时候被触发, 然后向服务器请求余下的数据
    LINAICAI
        11
    LINAICAI  
    OP
       2014-12-25 11:35:39 +08:00
    @icedx 根据您的提示 知道滑动的时候触发(function(){

    var loadImageOnScroll=_.throttle(function(){
    var bodyScrollTop = $("body").scrollTop() || $(window).scrollTop()
    var windowHeight = $(window).height();
    $("div.thumbnail img").each(function(){
    var $this = $(this)
    if(!$this.attr("src") && $this.offset().top<bodyScrollTop+windowHeight){
    $this.attr("src",$this.attr("data-src"));
    $this[0].onload=function(){
    $this.css("min-height","0")
    }
    }
    });
    },200)

    function domReady(){
    initPagenation();
    initSelectPic();
    initStar();
    ajax_get_star_info()
    if(!_u.isMobile()){
    setTimeout(showBigImgIfUrlIndicate,500)
    }
    $(window).scroll(loadImageOnScroll)
    }

    看这个 貌似得不到我想要的URL吧 接下来应该怎么做啊
    LINAICAI
        12
    LINAICAI  
    OP
       2014-12-25 11:39:58 +08:00
    @gamexg 那个明显的下一页的地址 我已经找到了 现在是加载一页并不是显示一页的数据 而是一部分 需要拉动浏览器到底部才一一加载全部数据
    python如何模拟这个拉动或者说滑动的动作?
    mornlight
        13
    mornlight  
       2014-12-25 11:52:01 +08:00
    我抓网页从不分析js,只看自己的操作和对应请求。
    看js太费力了,前面已经有人教你了,抓包看对应的请求是什么就行。不管怎么写页面,数据一般都是从HTTP请求过来的。
    抓包,抓包会吗?不是让你分析js。windows下如果不会用浏览器调试,请使用fiddler。
    imn1
        14
    imn1  
       2014-12-25 12:08:36 +08:00
    py模拟拖动是要加载 js 引擎的,而且客户端不同(宽高),往往方法就不同

    如果第九行不是ajax,而是js从数据生成,估计要运行个js引擎,或者直接从前面ajax获得的数据里面抠
    后者还好一点因为多是json,如果要运行js引擎我个人是懒得研究,成本太高,除非是个有钱收的项目
    Daniel65536
        15
    Daniel65536  
       2014-12-25 12:10:48 +08:00
    这说明在你滑到第九行之前,ajax已经请求了整个页面每一行的图片网址了,只是在第九行才开始加载图片罢了。
    你就不会查查那个请求下一页的ajax请求有没有返回所有的图片网址么?
    所有的图片的网址都已经被ajax发给你了,你还模拟个蛋啊。
    Daniel65536
        16
    Daniel65536  
       2014-12-25 12:12:07 +08:00
    去看看chrome的F12-Networking-Filter-XHR,这种爬虫最好搞了。
    icedx
        17
    icedx  
       2014-12-25 12:23:22 +08:00
    楼上已经说了我想说的了
    icedx
        18
    icedx  
       2014-12-25 12:30:57 +08:00
    LINAICAI
        19
    LINAICAI  
    OP
       2014-12-25 14:46:30 +08:00
    @icedx
    @Daniel65536
    @mornlight
    @gamexg
    感谢,多谢提醒,不一一谢了,先去干坏事~
    问题还是自己一时大意,原来是正则有漏洞,少爬了部分数据,导致以为只有8行数据
    icedx
        20
    icedx  
       2014-12-25 15:29:05 +08:00 via Android   ❤️ 1
    LINAICAI
        21
    LINAICAI  
    OP
       2014-12-25 15:40:34 +08:00
    @icedx 忽然觉得web开发比移动端开发酷多了 python好爽啊
    不错的IDE加语言能力 居然还可以直接操作远程数据库
    比OC用起来舒服
    icedx
        22
    icedx  
       2014-12-25 16:15:15 +08:00 via Android
    @LINAICAI
    其实坑挺深得 有可能一生也不理解Python 的哲学...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1041 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:18 · PVG 04:18 · LAX 12:18 · JFK 15:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.