欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网页爬虫修改js文件

程序员文章站 2022-03-08 15:44:13
...
  • 在爬取网页的时候要经常对js进行debug分析,selenium只做为测试工作使用,但是耗费资源高。目前很多网站的页面和报文都是通过js加密或者特殊处理生成,有些网站防爬策略是获取分辨率来判断的,最典型的应该是百度的防刷排名策略,就是通过分别率去判断,python或java是无法修改分别率的,比如说window.screen.height;比如说js文件中有个闭包方法里面的代码:


  • window.href = url+window.screen.height;

    java程序或者python程序无法通过修改window.screen.height来模拟参数,那么这就需要修改js文件window.href = url+1024;

    我们要在浏览器对js进行debug并且修改,修改完并通过console.log类似的功能输出指定的数据,那么java程序如何修改js代码?或者获取这些指定的数据?可以使用giant-htmlunit。
  • java代码
  • package test;
    
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.util.Map;
    
    import org.apache.commons.collections.map.HashedMap;
    
    import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
    import com.gargoylesoftware.htmlunit.fetch.FetchWebContext;
    import com.gargoylesoftware.htmlunit.html.HtmlPage;
    import com.gargoylesoftware.htmlunit.vo.fetch.ReloadContextVo;
    
    
    /**
     * 自制giant-htmlunit可以处理webclient多线程抓取网页,以便htmlunit更好的支持代理ip,拨号ip。节省更多的硬件资源。
     * 本用例用于测试 giant-htmlunit,处理js文件进行测试,(支持gzip流格式文件的修改)
     * context.asynCloseWebAllWindows();支持主线程异步关闭浏览器开启的job线程,htmlunit默认的close,是会等待job执行完毕的,不能预期关闭webclient,这样会大量占用内存跟线程资源,容易oom,asynCloseWebAllWindows很好的解决了该问题。
     * @author lyq
     */
    public class TestGiantClient {
    
    	public static void main(String[] args) throws FailingHttpStatusCodeException, MalformedURLException, IOException {
    
    //		updateJs();
    //		setWait();
    //		replaceJsResoure();//如果修改原始js太麻烦了,可以把js下载回来修改,修改完替换整个js
    		skipUrl();
    	}
    	
    	
    	
    
    	/**
    	 * @throws IOException 
    	 * cacheTest1.html 引入js1.js文件,修改js1.js代码,并执行。
    	 * 
    	 */
    	public static void updateJs() throws IOException{
    		
    		FetchWebContext context = new FetchWebContext();
    		ReloadContextVo contextVo = new ReloadContextVo();
    		
    		Map<String, ReloadContextVo> map = new HashedMap();
    		map.put("/js/js", contextVo);//识别url,如果url改变了,这个标识不变的情况下会重新加载js,比如说js/js1.js改成js2.js,最后会重新加载js2.js;现在流行单页面程序,像vue发布时候会重新生成js,加上后缀,这里正确设置,会重新加载最新的js
    		context.getFetchWebClient().cacheFile("/js/js");
    		contextVo.setStatic(true);//如果只替换一次,那么设置成true;如果需要动态替换,设置成false
    //		contextVo.add(arg0, arg1);
    		contextVo.add("(func1\\(\\)[\\w\\W]+?return\\s+?\")[\\w\\W]+?(\")","$1方法func1被修改了。。。$2");//类似 string。replaceAll方法,替换js代码
    		context.getFetchWebClient().setRegexToValue(map);
    		try{
    			HtmlPage page = (HtmlPage)context.getFetchWebClient().getPage("http://127.0.0.1:8085/test1/cacheTest1.html");
    			//			context.getFetchWebClient().set
    			 Object result = context.getFetchWebClient().getJavaScriptEngine().execute(page,"func1()" , "injected script", 1);
    			System.out.println(result);//这里输出“方法func1被修改了”
    		}catch(Exception e){
    			context.asynCloseWebAllWindows();
    		}
    	}
    	
    	/**
    	 * 
    	 * @throws IOException
    	 * testWait.html 引入js文件waitJs.js文件,主程序等待waitJs。js里面的代码执行完毕再继续跑。
    	 * addFilter× 与 waitFilter× 配对方法; 等待浏览器执行完js指定输出后再继续跑主程序
    	 */
    	public static void setWait() throws IOException{
    		FetchWebContext context = new FetchWebContext();
    		try{
    			context.getFetchWebClient().addFilterConsoleForStop("wait log1");
    			HtmlPage html = (HtmlPage)context.getFetchWebClient().getPage("http://127.0.0.1:8085/test1/testWait.html");
    //			context.getFetchWebClient().set
    			Long start = System.currentTimeMillis();
    			//这里找不到waitJs.js输出日志  "wait log1",所以会等待十秒钟,执行失败
     			context.getFetchWebClient().waitFilterConsoleForStop("wait log1", 10000);
    //			String result = context.getFetchWebClient().getConsoleResult();
     			
    			System.out.println(context.getFetchWebClient().getFilterUrlMap().size()+"花费时间:"+(System.currentTimeMillis()-start));
    			
    			
    			context.getFetchWebClient().addFilterConsoleForStop("wait log");
    			 html = (HtmlPage)context.getFetchWebClient().getPage("http://127.0.0.1:8085/test1/testWait.html");
    //			context.getFetchWebClient().set
    			 start = System.currentTimeMillis();
    			//这里找不到waitJs.js输出日志  "wait log1",所以会等待js输出 wait log,执行成功
     			context.getFetchWebClient().waitFilterConsoleForStop("wait log", 10000);
    //			String result = context.getFetchWebClient().getConsoleResult();
     			
    			System.out.println(context.getFetchWebClient().getFilterUrlMap().size()+"花费时间:"+(System.currentTimeMillis()-start));
    			
    		}catch(Exception e){
    			context.asynCloseWebAllWindows();
    		}
    	}
    	
    	
    	/**
    	 * @throws IOException 
    	 *testWait.html 引入js文件js1.js文件;主程序获取js2.js代替js1.js内容;
    	 * 
    	 */
    	public static void replaceJsResoure() throws IOException{
    		FetchWebContext context = new FetchWebContext();
    		ReloadContextVo vo = new ReloadContextVo();
    		context.getFetchWebClient().cacheFile("js/js");
    		try{
    			
    			context.url2url("http://127.0.0.1:8085/js/js1.js", "http://127.0.0.1:8085/js/js2.js");
    			context.getFetchWebClient().addFilterConsoleForResult("my result:");
    			HtmlPage html = (HtmlPage)context.getFetchWebClient().getPage("http://127.0.0.1:8085/test1/cacheTest1.html");
    //			context.getFetchWebClient().set
     			context.getFetchWebClient().waitFilterConsoleResult("my result:", 1000);
    			String result = context.getFetchWebClient().getConsoleResult();
    			System.out.println(result);//输出我是js2
    		}catch(Exception e){
    			context.asynCloseWebAllWindows();
    		}
    	}
    	
    	/**
    	 * @throws IOException 
    	 * 跳过指定路径不获取
    	 * 
    	 */
    	public static void skipUrl() throws IOException{
    		FetchWebContext context = new FetchWebContext();
    		ReloadContextVo vo = new ReloadContextVo();
    		try{
    			
    			context.getSkipUrls().add("/js/js");
    			HtmlPage html = (HtmlPage)context.getFetchWebClient().getPage("http://127.0.0.1:8085/test1/cacheTest1.html");
    			/***
    			 * 这里跳过了含/js/js了路径,也就是不会再获取js文件
    			 */
    			System.out.println(html);
    		}catch(Exception e){
    			e.printStackTrace();
    			context.asynCloseWebAllWindows();
    		}
    	}
    }
    
    
    





  • 通过maven导入该工具
  • <dependency>
    			<groupId>com.giant</groupId>
    			<artifactId>giant-htmlunit</artifactId>
    			<version>2.26.8</version>
    			<scope>compile</scope>
    		</dependency>
    
    <!--如果raw.githubusercontent.com不能下载参照https://blog.csdn.net/Mirt_/article/details/106011435-->
    <repository>
    		    <id>framework</id>
    			<name>framework</name>
    			<url>https://raw.githubusercontent.com/jzft/framework/master/repository/</url>
    			 <snapshots>
    				<enabled>false</enabled>
    			</snapshots> 
    	</repository>
    


  • 准备访问的html
  • //cacheTest1.html代码
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>cacheTest1.html</title>
    </head>
    <body>
    <script src="/js/js1.js"></script>
    </body>
    </html>
    


    //cacheTest2.html代码
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>cacheTest2.html</title>
    </head>
    <body>
    <script src="/js/js2.js"></script>
    </body>
    </html>
    
    
    


    //testWait.html代码
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>TestWait</title>
    </head>
    <body>
    <script src="/js/waitJs.js"></script>
    </body>
    </html>
    </html>
    
    
    


  • html引用的js

  • //js1.js代码
    console.log("my result:我是js1")
    
    function func1(){
    	return "func1 execute"
    }
    


    //js2.js代码
    console.log("my result:我是js2")
    


    //waitJs.js代码
    setTimeout(function(){
    	console.log("wait log !"); 
    },3000)