简单爬虫项目总结_01

                                                      


首先讲下这个项目的功能,及所用到的技术,

   1:因怕爬去网页时ip被封,所以用到了代理ip接口,这个接口每请求一次会返回十个ip,及对应端口号 将其split后add进list


2:有了代理ip,下面就可以对网页放心的操作了,但是这时问题来了,并不是所有的代理ip都能用,一旦碰到无用ip就重新请求就太浪费资源,而list直接remove掉无用的元素,再continue到下一次for循环中就会报错

通俗的讲就是list 不允许在遍历的同时remove他的元素  网上找的说法是:

API中此异常的解释:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

原因:

Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 Java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
个人的理解是操作的元素销毁了,但是指向这个元素的索引还在,所以再便利时找不到元素就会报错。

解决方案也是在网上找的例子,用迭代器对list中的元素进行操作

	Iterator<String[]> iterator = daiLiIp.iterator();
		while (iterator.hasNext()) {
			
			String[] ss = iterator.next();
			String ip = ss[0];
			String num = ss[1];
			int port = 0;
			try {
				port = Integer.parseInt(num);
			} catch (NumberFormatException e) {
				log.debug("GetSoundCodeUtil类:"+e.getMessage());
			}

			String connectState = getSoundCode(ip, port, url, codingFormat);// 连接状态只有为false时是连接失败
			if ("false".equals(connectState)) {
				daiLiIp.remove(ss); // 移除list中无用ip
				iterator = null;// 重新置空迭代器
				System.gc();// 垃圾回收
				iterator = daiLiIp.iterator();// 迭代器重新赋值
				
				if (daiLiIp.size() == 0) {// 如果代理ip集合为0就重新调接口
					daiLiIp = GetDaiLiIpUtil.getDaiLiIp();
					iterator = daiLiIp.iterator();
				}
				continue;// 进入下次循环
			} else {
				return connectState;// 停止循环
			}
		}

		return null;
3:对网页的爬取:

      (1):只爬取页面上的数据 用HttpClient 简历连接拿到网页源码

//创建HttpClient对象
		HttpClient http = new DefaultHttpClient();
		//设置相应时间,设置获取源码时间,设置代理服务器
		http.getParams()
		.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,100000)//连接超时 指的是连接一个url的连接等待时间
		.setParameter(CoreConnectionPNames.SO_TIMEOUT, 100000)//等待客户连接的超时时间
		.setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("ip",端口号));
		//创建请求对象,get还是post看情况
		HttpGet hGet = new HttpGet("http://js.avis.cn/sources/cityshopsdata.js?version=20170301162501");
		HttpResponse response = http.execute(hGet);
		//EntityUtils工具类把网页实体转换成字符串
		String str = EntityUtils.toString(response.getEntity(),"utf-8");
//拿到网页源码再对其进行解析
Elements code = GetElementsUtil.getElements(网页源码,"要拿到的标签交id或class(ul.titles.l");
		for (Element entityCode : code) {//可以继续对拿到的标签进行解析}

(2)爬取到json字符串数据:

如果需要带cookie信息才能拿到数据可以在向父网站发送请求时

Header[] cookies= response.getHeaders("set-cookie");
获取cookie,在向子网站发送请求时携带cookie

 

hget.addHeader("Cookie",cookie);

        截取出有效的json字符,再将字符串转为实体类,在定义实体类时要完全按着json属性定义

@JsonProperty(value = "address")
	private String address;
再用ObjectMapper将json字符串转为实体类

		List<JsonObject> cityStoreList = null;
			ObjectMapper oMapper = new ObjectMapper();
			try {
				// json字符串转对象
				cityStoreList = oMapper.readValue(cityJson,
						new TypeReference<List<EntityObject>>() {
						});
				if (cityStoreList != null && cityStoreList.size() > 0) {
					//对含实体类对象的list进行操作
				}
				} else {
					log.debug("");
				}
			} catch (Exception e) {
				log.debug(e.getMessage());

			}
			

拿到数据再入库,或者导入excel

这个项目用了配置文件 


第一次在项目中运用配置文件,在一些可能会变更的地方用配置操作,个人感觉配置文件方便了代码的维护

错误日志用的log4j网上找的方案



                                                                                                                    奋斗坚持每个项目都写一个


     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值