webmagic 原理与典型应用场景分析实现

本文详述WebMagic框架处理多种URL形式,包括绝对链接、相对链接及动态JS/Ajax请求,介绍如何实现系统登录与Cookie获取,以及数据结构化存储方法,适合爬虫开发者参考。

 

1. webmagic抓取URL原理

 url形式多样,一个网页里包含的url 简单列举为以下情形:

1)绝对链接url, 形如https://i.csdn.net/#/uc/profile,返回为html网页。

2)相对url,如 " /etc/info/index.jsp ", 其完整网址需要和当前页面地址拼凑而来

3)动态js/ajax请求,如http://48.98.121.251:9000/iLamp/lampindex/rate,返回为json结果。

webmagic抓取当前页面url添加到后续队列语句:

page.addTargetRequests(page.getHtml().links().all());

那么 webmagic可以抓取全部格式的url吗?看page的getHtml方法,此方法先获得html页面,返回html对象

 /** get html content of page
     * @return html
     */
    public Html getHtml() {
        //如果html为空,说明返回的不是html文件,可能是ajax返回的json值,结果存放在rawText  
        if (html == null) {
            html = new Html(UrlUtils.fixAllRelativeHrefs(rawText, request.getUrl()));
        }
        //如果不为空,则获得的页面为html网页
        return html;
    }

然后html.links(),Html继承自HtmlNode  : public class Html extends HtmlNode

public class HtmlNode extends AbstractSelectable {

    //links方法
    @Override
    public Selectable links() {
        return xpath("//a/@href");
    }
}

此处可以看出,webmagic本质上获取当前页链接,只是获得了格式为<a href="url">的url。

2.添加非标准url地址(需要自行添加)

2.1 相对url 

正则匹配获得相对url /etc/info/index.jsp ,结合当前页拼凑完整url:http://48.50.192.121/etc/info/index.jsp 添加到targetRequest.

2.2 动态js/get方式Ajax请求

   get方式ajax请求,可以直接把ajax请求的地址,添加到待处理队列。

 page.addTargetRequest("http://48.90.120.241:9000/iLamp/mobile/device/weatherHefeng?cityNum=CN101190104");

2.3 动态js/post方式url

新建request,设置POST请求。

 Request request=new Request("http://48.91.121.241:9000/iLamp/lampindex/rate");
		 request.setMethod(HttpConstant.Method.POST);
		 page.addTargetRequest(request);

动态url分析获取,可以调用chrome调试工具,network-response-xhr , 就可以看到浏览过程汇总访问的接口。

 3 系统登录与Cookie获取

 配置 selenium ,根据标签获得输入框和确定键,输入账户密码,点击登录。获得cookies

//使用 selenium 来模拟用户的登录获取cookie信息 
	
	public void login() { 
		WebDriver driver = new ChromeDriver(); 
		driver.get("http://48.98.121.241:9000/iLamp/index.jsp"); 
		driver.findElement(By.name("username")).clear();
		driver.findElement(By.name("username")).sendKeys("00000000");
		driver.findElement(By.name("password")).clear();
		driver.findElement(By.name("password")).sendKeys("12345");
		
		driver.findElement(By.id("login-btn")).click(); //获取cookie信息 
		
		cookies = driver.manage().getCookies(); 
		driver.close(); 
		} 

再次访问网页,需要携带之前获得的cookie,site自带addCookies方法,但我用此方法添加的cookie并不能通过验证

for (Cookie cookie : cookies) { 
		site.addCookie(cookie.getName().toString(),cookie.getValue().toString());
}

通过postman请求发现,在请求头里,新建Cookie,然后添加登陆获得的cookie信息,可以通过验证,由于我的cookie内容只有jession和lamp-nari-shiro有效,故Cookie里只添加了这两个信息。代码如下

	for (Cookie cookie : cookies) { 
		if(cookie.getName().equals("JSESSIONID")) {
			Cookie +=cookie.getName()+"="+cookie.getValue().toString()+";";
		}
		if(cookie.getName().equals("ilamp-nari-shiro")) {
			Cookie +=cookie.getName()+"="+cookie.getValue().toString()+";";
		}
		} 

至此,登录过程与cookie验证已经完成。 

4. 数据结构化存储

4.1 建立带提取数据类

public class WeatherDao {

	private String riseTime;
	
	private String downTime;
	
	private String city;
}

4.2 progress中把关键字段putFiled

 if(page.getUrl().get().equals("http://48.91.121.241:9000/iLamp/mobile/device/weatherHefeng?cityNum=CN101190104")) {
			 String downTime = new JsonPathSelector("$.downTime").select(page.getRawText());
			 String city = new JsonPathSelector("$.city").select(page.getRawText());
			 String riseTime = new JsonPathSelector("$.riseTime").select(page.getRawText());

			 page.putField("downTime",downTime );
			 page.putField("city",city );
			 page.putField("riseTime", riseTime);

4.3 Spider启动时添加pipeLine,pipeLine中完成处理逻辑

 启动时加入pipeline

Spider.create(miai).addPipeline(new WeatherPipeline()) .addUrl("https://www.oschina.net/").thread(1) .run();

 pipeline处理逻辑

public class WeatherPipeline implements Pipeline{

	public WeatherPipeline() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void process(ResultItems resultItems, Task task) {
		// TODO Auto-generated method stub
		String city="";
		String riseTime="";
		String downTime="";
	for(Entry enty:resultItems.getAll().entrySet()) {
		if(enty.getKey()!=null&&((String)enty.getKey()).equals("city")) {
			 city = (String)enty.getValue();
		}
		if(enty.getKey()!=null&&((String)enty.getKey()).equals("riseTime")) {
			 riseTime = (String)enty.getValue();
		}
		if(enty.getKey()!=null&&((String)enty.getKey()).equals("downTime")) {
			 downTime = (String)enty.getValue();
		}
		WeatherDao weather =new WeatherDao();
		weather.setCity(city);
		weather.setDownTime(downTime);
		weather.setRiseTime(riseTime);
		//后续持久化逻辑,存数据库或者文件或redis等内存数据库
		
	}
	}

}

 欢迎相互讨论,交流学习。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值