Mini Mango 2023-02-02 11:17 采纳率: 80%
浏览 41
已结题

#爬虫webmagic#使用PriorityBlockingQueue出现排序失灵,如何解决?

最近用的webmagic做垂直爬虫,对方网页是通过js动态加载,不能直接爬html的,所以是从F12里面的Network,抓包拿到网址,再发送请求拿到的数据。

因为要做请求排序,我模仿了PriorityScheduler,自定义了一个Scheduler:

下面的代码里面:
level:记录爬取深度
pageNum:记录分页的页码
literatureNum:记录文章的顺序
textIndex:记录全文的内容(因为全文是分开很多个图片,上面无页码,所以从第一页到最后一页,要记录)
爬取的逻辑是,先有pageNum,再有literatureNum,最后有textIndex,
但爬虫顺序优先级是textIndex>literatureNum>pageNum。
对应的深度:pageNum的level是0,literatureNum的level是1,textIndex的level是2

用的PriorityBlockingQueue做任务队列:

package com.huada.priorityScheduler;

import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.scheduler.DuplicateRemovedScheduler;
import us.codecraft.webmagic.scheduler.MonitorableScheduler;

import java.util.concurrent.PriorityBlockingQueue;

/**
 * Priority scheduler. Request with higher priority will poll earlier. <br>
 *
 * @author code4crafter@gmail.com <br>
 * @since 0.2.1
 */
public class MyQueueScheduler extends DuplicateRemovedScheduler implements MonitorableScheduler {

    public static final int INITIAL_CAPACITY = 100;

    private final PriorityBlockingQueue<Request> priorityQueue = new PriorityBlockingQueue<>(INITIAL_CAPACITY, (o1, o2) -> {
        //比较优先级,越大越优先
        if ((int) o1.getExtra("level") != (int) o2.getExtra("level")) return (int) o2.getExtra("level") - (int) o1.getExtra("level");
        //比较页数,页数越小越优先
        if ((int) o1.getExtra("pageNum") != (int) o2.getExtra("pageNum")) return (int) o1.getExtra("pageNum") - (int) o2.getExtra("pageNum");
        //比较文章顺序,文章顺序越前(小)越优先
        if ((int) o1.getExtra("literatureNum") != (int) o2.getExtra("literatureNum")) return (int) o1.getExtra("literatureNum") - (int) o2.getExtra("literatureNum");
        //比较全文图片索引,索引越小越优先
        if ((int) o1.getExtra("textIndex") != (int) o2.getExtra("textIndex")) return (int) o1.getExtra("textIndex") - (int) o2.getExtra("textIndex");
        return 0;
    });

    @Override
    public void pushWhenNoDuplicate(Request request, Task task) {
        priorityQueue.put(request);
    }

    @Override
    public synchronized Request poll(Task task) {
        return priorityQueue.poll();
    }

    @Override
    public int getLeftRequestsCount(Task task) {
        return priorityQueue.size();
    }

    @Override
    public int getTotalRequestsCount(Task task) {
        return getDuplicateRemover().getTotalRequestsCount(task);
    }
}

但是最后的排序结果很诡异,排序很乱,不知道为什么:

img

后面我不用PriorityBlockingQueue,用的CopyOnWriteArrayList,排序则正常,结果如下:

package com.huada.priorityScheduler;

import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.scheduler.DuplicateRemovedScheduler;
import us.codecraft.webmagic.scheduler.MonitorableScheduler;

import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 自定义任务队列
 */
public class MyArrayListScheduler extends DuplicateRemovedScheduler implements MonitorableScheduler {

    private static CopyOnWriteArrayList<Request> priorityList = new CopyOnWriteArrayList<>();

    @Override
    public void pushWhenNoDuplicate(Request request, Task task) {
        priorityList.add(request);
    }


    @Override
    public synchronized Request poll(Task task) {
        if (priorityList.size() == 0) return null;
        if (priorityList.size() >= 2) {
            priorityList.sort((o1, o2) -> {
                //比较优先级,越大越优先
                if ((int) o1.getExtra("level") != (int) o2.getExtra("level")) return (int) o2.getExtra("level") - (int) o1.getExtra("level");
                //比较页数,页数越小越优先
                if ((int) o1.getExtra("pageNum") != (int) o2.getExtra("pageNum")) return (int) o1.getExtra("pageNum") - (int) o2.getExtra("pageNum");
                //比较文章顺序,文章顺序越前(小)越优先
                if ((int) o1.getExtra("literatureNum") != (int) o2.getExtra("literatureNum")) return (int) o1.getExtra("literatureNum") - (int) o2.getExtra("literatureNum");
                //比较全文图片索引,索引越小越优先
                if ((int) o1.getExtra("textIndex") != (int) o2.getExtra("textIndex")) return (int) o1.getExtra("textIndex") - (int) o2.getExtra("textIndex");
                return 0;
            });
        }
        Request req = priorityList.get(0);
        priorityList.remove(0);
        return req;
    }

    @Override
    public int getLeftRequestsCount(Task task) {
        return priorityList.size();
    }

    @Override
    public int getTotalRequestsCount(Task task) {
        return getDuplicateRemover().getTotalRequestsCount(task);
    }
}

img

img

所以用PriorityBlockingQueue为什么会出现排序失灵的情况?

  • 写回答

2条回答 默认 最新

  • 紫荆桥下 2023-02-03 18:04
    关注

    PriorityBlockingQueue是一个无界的、线程安全的、可排序的队列,它使用了优先级队列的内部实现。在队列中添加元素时,会根据元素的优先级进行排序,使得在出队的时候,优先级最高的元素先出队。
    PriorityBlockingQueue可能会出现排序失灵的情况,这是因为在添加元素时没有任何同步措施,多个线程同时添加元素可能导致排序失灵。另外,如果元素的优先级相同,则无法保证元素的出队顺序。如果出现排序失灵的情况,可以尝试以下几种解决方案:

    1. 使用同步机制来控制PriorityBlockingQueue的访问,保证在操作队列的时候其他线程无法访问;

    2. 使用Collections.sort()方法来重新排序队列中的元素;

    3. 将PriorityBlockingQueue中的元素拷贝到一个新的集合中,然后利用Collections.sort()方法对元素进行排序,最后清空原来的PriorityBlockingQueue,将排好序的元素重新放入;

    4. 使用Comparable接口重新实现比较器,以确保PriorityBlockingQueue中的元素按照正确的顺序排列。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 2月24日
  • 已采纳回答 2月16日
  • 修改了问题 2月2日
  • 修改了问题 2月2日
  • 展开全部

悬赏问题

  • ¥15 各位请问平行检验趋势图这样要怎么调整?说标准差差异太大了
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 wpf界面一直接收PLC给过来的信号,导致UI界面操作起来会卡顿
  • ¥15 init i2c:2 freq:100000[MAIXPY]: find ov2640[MAIXPY]: find ov sensor是main文件哪里有问题吗
  • ¥15 运动想象脑电信号数据集.vhdr
  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab