关于在多线程情况下同步爬虫爬取结果的一个例子
2017-01-24 14:13
507 查看
这些天一直在用java做爬虫工作,之前遇到的都比较简单,大多都是单界面的爬取,这次需要爬虫100多个界面,肯定得多跑几个线程然而这些界面由于信息中有重复,leader要求我们必须去重,因为数据库更改是有次数限制的。所以搞了几天,才把这个程序写出来。先写一下思想:首先,利用JAVA自己带的线程安全的集合,ConcurrentHashMap进行一个自动去重的工作。但是在多线程情况下,一定要注意线程同步,集合类的线程安全,仅仅是存的时候是锁住的,这不代表我们在进行条件判断时候也是线程安全的,这就需要我们自己对需要同步的代码块上锁。
public static ConcurrentHashMap<String,Integer> hashMap=new ConcurrentHashMap<String, Integer>(); AtomicInteger integer = new AtomicInteger(); public void process(Page page) { if(page.getUrl().toString()=="https://www.toryburch.com/stores-viewal") { for (String a : url) { page.addTargetRequest(a); } } else { String shopId = ""; String branchName = ""; StringBuffer address = new StringBuffer(); String crawlUrl = ""; String region = ""; String city = ""; String country = "the United States"; String shopName = "LanCome"; String sourceName = "LanCome"; String phone = ""; String openTime = ""; double lat = 0.0; double lng = 0.0; List<Selectable> infoList=page.getHtml().xpath("poi").nodes(); List<BrandPoiDto> brandPoiDtos =new ArrayList<BrandPoiDto>(); //防止有些没有获取到商户信息, if(infoList.size()>=1) { for(Selectable b:infoList) { phone=b.xpath("//phone/text()").toString(); shopId=b.xpath("//uid/text()").toString(); city=b.xpath("//city/text()").toString(); branchName=b.xpath("//name/text()").toString(); lat=Double.parseDouble(b.xpath("//latitude/text()").toString()); lng=Double.parseDouble(b.xpath("//longitude/text()").toString()); //提取地址:包含address1和address2 address=address.append(b.xpath("//address1/text()").toString()).append(b.xpath("//address2/text()").toString()); < 4000 span style="color:rgb(204,120,50);"> BrandPoiDto dto = new BrandPoiDto(); dto.setBranchName(branchName); dto.setAddress(address.toString()); dto.setCrawlUrl(page.getUrl().toString()); dto.setCity(city); dto.setCountry(country); dto.setPhone(phone); dto.setLat(lat); dto.setLng(lng); dto.setShopName(shopName); dto.setSourceName(sourceName); dto.setShopId(shopId); synchronized (this) { if(hashMap.get(shopId)==null) { hashMap.put(shopId,1); brandPoiDtos.add(dto); System.out.println(dto); integer.incrementAndGet(); } } //对数据进行清除 address.delete(0,address.length()); phone=""; lat=0.0; lng=0.0; shopId=""; branchName=""; city=""; } } //之后要入库操作 System.out.println("总共抓取数量为"+integer); }代码如下,我用synchronized同步的代码块,先判断在hashMap中有没有这个信息(key为商户uid,是唯一的),如果没有,则将数据存入,并设置标志位1,如果有的话,就不进行存储和打印验证了。通过同步代码块和用hashmap,解决了多个线程抓取时重复数据的去重问题。
相关文章推荐
- 关于多线程的一个例子(UI实时显示)
- Linux多线程编程(不限Linux)——本文一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥。
- 关于多线程的一个例子
- 关于同步、异步、阻塞、非阻塞一个通俗易懂的例子
- 本文一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥
- 关于多线程程序中使用volatile关键字的一个小例子
- 一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥。
- 关于多线程的一个例子(UI实时显示)
- 一个关于多线程的简单例子(两种实现方法)
- 下面的例子演示了100个线程同时向一个银行账户中存入1元钱,在没有使用同步机制和使用同步机制情况下的执行情况。
- Delphi多线程的OnTerminate属性(附加一个关于临界区线程同步的例子)
- ABC线程如何保证顺序执行 关于多线程的一个小例子
- *Delphi多线程的OnTerminate属性(附加一个关于临界区线程同步的例子)
- 关于多线程的一个例子(UI实时显示)
- 一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥。
- 关于多线程的一个例子(UI实时显示)
- 关于多线程的一个例子(UI实时显示)
- 关于多线程的一个例子(UI实时显示)
- 一个关于反射的小例子
- 关于一个多线程、断点续传的FTP服务程序!