Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
0 / 0 / 0
Регистрация: 09.10.2014
Сообщений: 7

Многопоточный HTML Парсер

26.11.2014, 23:42. Показов 2672. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Суть задачи состоит в том чтобы парсить html по ссылке на наличие email-ов, в случае наличия таковых, выводим ссылку и email-ы которые нашли на ней, потом парсим эту же ссылку на наличие других ссылок, и для этих ссылок проводим аналогичные дейтсвия, по получившим ссылкам опять те же действия. В моем случае все закончиться только тогда когда закончатся уникальные ссылки, пока есть уникальные ссылки мы будем создавать для них новые задачи. Использую ThreadPoolExecutor для обработки ссылок.

Проблема: Как реализовать контроль глубины поиска, то есть если я хочу чтобы глубина поиска была равна 2, то для первой ссылки, мы парсим mail-ы, потом другие ссылки, а для других ссылок парсим mail-ы и на этом все, новые задачи не создаются.

Еще одна проблема заключается в выполнении shutdown(). Мне нужен какой-то аналог который не блокирует создания новых задач, и вырубает пул только тогда, когда все задачи отработаны, и пул пуст. Или может какой-то другой подход, но чтобы он был не блокирующим.

Возможны другие предложения по организации данного процесса.

Код:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
public class AppGUI {
 
    private JFrame myFrame;
    private JPanel myPanel;
    private JPanel btnPanel;
    private JButton btnParse;
    private JTextField urlTextField;
    private JTextArea outcomeTextArea;
    private JScrollPane outcomeScroll;
    
    private HTMLParser parser = new HTMLParser();
    
    private Set<String> allLinks;
    private String host;
    private static final int THREADS_COUNT = 10;
    
    //private ExecutorService executor;
    private static TPExecutor executor;
    private Lock lock = new ReentrantLock();
    
    public void createGUI() {
        myFrame = new JFrame();
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setSize(400,400);
        
        btnPanel = new JPanel();
        
        btnParse = new JButton("Parse");
        btnParse.addActionListener(new ButtonClickListener());
        btnPanel.add(btnParse);
        
        myPanel = new JPanel(new BorderLayout());
        myPanel.add(btnPanel, BorderLayout.SOUTH);
        
        urlTextField = new JTextField();
        myPanel.add(urlTextField, BorderLayout.NORTH);
        urlTextField.setText("http://www.nmu.org.ua/ua/");
        
        outcomeTextArea = new JTextArea();
        
        outcomeScroll = new JScrollPane(outcomeTextArea);
        outcomeScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        outcomeScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        myPanel.add(outcomeScroll, BorderLayout.CENTER);
        
        myFrame.getContentPane().add(myPanel);
        myFrame.setVisible(true);
    }
    
    public String getHost (URL page){
        String host = page.getHost().toLowerCase();
        if (host.startsWith("www.")){
            host = host.substring("www.".length());
        }
        return host;
    }
    
    class ButtonClickListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent arg0) {
            if (btnParse.getText().equals("Parse")){
                outcomeTextArea.setText("");
                allLinks = new LinkedHashSet<>();
                allLinks.add(urlTextField.getText());
                //executor = Executors.newFixedThreadPool(10);
                executor = new TPExecutor(THREADS_COUNT, THREADS_COUNT, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
                try {
                    URL url = new URL(urlTextField.getText());
                    host = getHost(url);
                    executor.setStartTime(System.currentTimeMillis());
                    outcomeTextArea.append("Parsing started...\n\n");
                    executor.execute(new MyRunnable(url, host));
                    btnParse.setText("Stop");
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(myFrame, "Invalid URL","Error", JOptionPane.OK_OPTION);
                }
                //executer.shutdown() блокирует создание новых задачь, ждет завершения активных задач и отрубает пул.
                //а нужно чтобы ждало завершения активных задач без блокирования создания новых.
            } else
            if (btnParse.getText().equals("Stop")){
                executor.shutdownNow();
                btnParse.setText("Parse");
            }
        }
    }
    
    class TPExecutor extends ThreadPoolExecutor{
 
        private long startTime;
        
        public TPExecutor(int corePoolSize, int maximumPoolSize,
                long keepAliveTime, TimeUnit unit,
                BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }
        
        public void setStartTime(long startTime) {
            this.startTime = startTime;
        }
        
        @Override
        protected void terminated() { 
                outcomeTextArea.append("Parsing completed. Total time: "    + (System.currentTimeMillis() - startTime) / 1000 + " sec.");
        }
    }
    
    class MyRunnable implements Runnable{
        
        URL url;
        String host;
        
        public MyRunnable(URL url, String host){
            this.url = url;
            this.host = host;
        }
 
        @Override
        public void run() {
            try {
                Set<String> emails = parser.getEmails(url);
                if (!emails.isEmpty()){
                    lock.lock();
                    try{
                        outcomeTextArea.append(url.toString()+"\n");
                        for (String e:emails){
                            outcomeTextArea.append(e+"\n");
                        }
                        outcomeTextArea.append("\n");
                    }
                    finally {lock.unlock();}
                }
                Set<String> links = parser.getLinks(url, host);
                for (String l:links){
                    if(allLinks.add(l) == true){
                        executor.execute(new MyRunnable(new URL(l), host));
                    };
                }
            } catch (IOException | BadLocationException e) {
                e.printStackTrace();
            }
            
        }
        
    }
    
}
Добавлено через 54 минуты
Короче тема закрыта, все решил.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.11.2014, 23:42
Ответы с готовыми решениями:

Многопоточный .csv парсер
Доброго времени суток) Суть вопроса думаю понятна из заголовка. файл .csv содержит строки типа ...

Многопоточный парсер, как организовать?
Привет всем зашедшим. Вот такая задача есть. Организовать что-то вроде мнoгoпoтoчного пapсера. Который будет следить за определенной...

Парсер html на java
Пытаюсь написать парсер html. Подсматриваю на другом сайте (del) Согласно данному источнику у меня в импорте должны быть строчки: ...

2
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
26.11.2014, 23:58
Цитата Сообщение от IamMax Посмотреть сообщение
Как реализовать контроль глубины поиска, то есть если я хочу чтобы глубина поиска была равна 2
В класс MyRunnable добавить новое поле (и параметр в конструктор) - текущая глубина.
Цитата Сообщение от IamMax Посмотреть сообщение
Еще одна проблема заключается в выполнении shutdown(). Мне нужен какой-то аналог который не блокирует создания новых задач, и вырубает пул только тогда, когда все задачи отработаны, и пул пуст. Или может какой-то другой подход, но чтобы он был не блокирующим.
Предлагаю выставить corePoolSize у ThreadPoolExecutor в 0 - тогда потоки пула сами завершатся, после завершения всех тасок и таймаута. keepAliveTime только поставьте не 0.

Цитата Сообщение от IamMax Посмотреть сообщение
outcomeTextArea.append(url.toString()+"\ n");
Так делать нехорошо: к swing компонентами нельзя обращаться из не-UI потока. Нужно использовать SwingUtilities.invokeAndWait/ivokeLater для доступа к GUI из других потоков.
Ваш lock тогда можно выкинуть. Если вам надо сгруппировать email-ы с каждой страницы - просто добавить их сначала в локальный StringBuilder, а потом одним запросом SwingUtilities добавите в outcomeTextArea

Не по теме:

PS. Спамеры должны гореть в аду :)



Добавлено через 6 минут
Еще заметил проблему: LinkedHashSet - не потоко-безопасная коллекция. Нельзя просто так вызывать add на нем из разных потоков - огребёте проблем.
Замените его на ConcurrentHashMap или Collections.newSetFrom(new ConcurrentHashMap<String,Boolean>()) или Collections.synchronizedSet(new LinkedHashSet<String>());
1
0 / 0 / 0
Регистрация: 09.10.2014
Сообщений: 7
27.11.2014, 18:57  [ТС]
Спасибо, по компонентам, вроде знал, но затупил ибо новичек. По поводу глубины, так и решил. Все остальное буду исправлять, еще раз спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
27.11.2014, 18:57
Помогаю со студенческими работами здесь

парсер html страницы
Здраствуйте есть вот такой участок кода static public String getSomeUrl(final String url) throws URISyntaxException, IOException,...

парсер html страницы
Здраствуйте. пытаюсь спарсить исходник одной html страницы мне нужно выдернуть из нее только ссылку на mp4 файл парсер пишу под...

парсер html страницы
Здраствуйте. Пытаюсь написать парсер под android для html страницы, чтобы выдернуть оттуда линк. Выглядит все так: ... фигня ...

Многопоточный парсер
Пытаюсь создать многопоточный парсер, но появилась проблема. Пытался сделать через Thread + делегат и через task, но при использовании: ...

Многопоточный парсер по ftp
Есть удаленный сервер, куда есть коннект по ftp, требуется рекурсивно парсить около (700К) файлов (маска имени, контент файлов итд ). Объем...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru