Добрый день.
Парсю страницу, на которой 30 фильмов.
Потом поочердно парсю страницу каждого фильма следующим методом:
static Film GetFilm(int id) throws URISyntaxException, InterruptedException, IOException, LoaderException
{
URI uri = new URI("https://www.ivi.ru/watch/"+id);
HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.NORMAL).build();
HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
Pattern pattern = Pattern.compile(
"<div\\sclass=\"contentCard__info\">.*?"
+ "<h1\\sclass=\"watchTitle__title.*?\">(.*?)</h1></div>" // 1 - name
+ "<div.*?class=\"watchParams\\scontentCard__watchParams\">"
+ "<ul.*?class=\"watchParams__paramsList\">"
+ "<div.*?class=\"watchParams__item\">"
+ "<a.*?>(.*?)</a></div>" // 2 - year
+ "<div.*?class=\"watchParams__item\">"
+ "<a.*?data-test=\"content-duration\".*?>"
+ "(.*?)</a></div>" // 3 - duration
+ "<div.*?class=\"watchParams__item\">"
+ "<a.*?>(.*?)</a></div>" // 4 - ageCategory
+ "</ul>"
+ "<ul.*?class=\"watchParams__paramsList\">"
+ "<div.*?class=\"watchParams__item\\s+watchParams__item_hasDot\">"
+ "<a.*?>(.*?)</a></div>" // 5 - country
+ "<div.*?class=\"watchParams__item\\s+watchParams__item_hasDot\">"
+ "<a.*?>(.*?)</a></div>" // 6 - category
);
Matcher matcher = pattern.matcher(response.body());
if(!matcher.find()) return null;
System.out.println(Thread.currentThread().getName()+" yes get film:"+id);
Pattern pattern2 = Pattern.compile("(\\d+)");
Matcher matcher2 = pattern2.matcher(matcher.group(3));
if(!matcher2.find()) throw new LoaderException("Cannot parse the duration");
int duration = Integer.parseInt(matcher2.group(1))*60+Integer.parseInt(matcher.group(2)); // hours and mins to mins
Matcher matcher3 = pattern2.matcher(matcher.group(4));
if(!matcher3.find()) throw new LoaderException("Cannot parse age category");
int ageCategory = Integer.parseInt(matcher3.group(1));
Film film = new Film();
film.SetName(matcher.group(1));
film.SetYear(Integer.parseInt(matcher.group(2)));
film.SetDuration(duration);
film.SetAgeCategory(ageCategory);
film.SetCountry(matcher.group(5));
film.SetCategory(matcher.group(6));
return film;
}
Вызываю данный код последовательно:
List<Integer> filmsIds = new ArrayList<>();
String address = "https://www.ivi.ru/collections/movies-highrated";
filmsIds.addAll(Loader.GetFilmList(address));
List<Film> films = new ArrayList<>();
for(int id:filmsIds)
{
films.add(Loader.GetFilm(id));
}
System.out.println(films.size());
Выдает, что распарсил все 30 фильмов.
Вызываю этот метод параллельно:
List<Integer> filmsIds = new ArrayList<>();
String address = "https://www.ivi.ru/collections/movies-highrated";
filmsIds.addAll(Loader.GetFilmList(address));
List<Callable<Film>> tasks = new ArrayList<Callable<Film>>();
for(int id:filmsIds)
{
Callable<Film> task = ()->Loader.GetFilm(id);
tasks.add(task);
}
ExecutorService executor = Executors.newCachedThreadPool();
List<Future<Film>> results = executor.invokeAll(tasks);
for(var res:results)
{
if(res.get()!=null)
System.out.println(res.get().getName());
}
Выдает, что распарсил 25 фильмов.
В чем причина?
Если указать в функции, в случае невозможности распарсить фильм выдавать ошибку, а не null как сейчас, то при параллельном вычислении выдает ошибку, а при последовательном нет.
UPD: при параллельном парсинге срабатывает условие if(!matcher.find()) return null; (раньше там делал выброс ошибки, но тогда обрывается выполнение остальных потоков)
Но срабатывает не на всех фильмах, примерно 25 (из 30) штук парсятся.
При последовательном выполнении парсятся все.