Парсинг сайта и создание json файла
Не получается разобраться с парсингом
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CreateJson {
public static String createMap(String resultMap) throws Exception {
Document doc = Jsoup.connect("https://skillbox-java.github.io/").get();
JSONObject objParent = new JSONObject();
JSONObject list = new JSONObject();
for (Element stations : doc.select("span.js-metro-line.t-metrostation-list-header.t-icon-metroln")) {
for (Element lines : doc.select("p.single-station")){
JSONArray linesName = new JSONArray();
String Lines = lines.text();
String Name = stations.text();
linesName.put(Lines);
list.put(Name, linesName);
}
}
objParent.put("stations",list);
Files.write(Paths.get(resultMap), objParent.toString().getBytes(StandardCharsets.UTF_8));
return objParent.toString();
}
}
Результат json файла такой:
{
"stations":{
"Калининско-Солнцевская линия":[
"35. Подольск"
],
"Арбатско-Покровская линия":[
"35. Подольск"
],
"Кольцевая линия":[
"35. Подольск"
],..
}
}
А должен выглядеть так:
{
"stations":{
"Калининско-Солнцевская линия":[
"1. Новокосино",
"2. Новогиреево",
"3. Перово", ...
],
"Арбатско-Покровская линия":[
"1. Пятницкое шоссе",
"2. Митино",
"3. Волоколамская",...
],
"Кольцевая линия":[
"1. Киевская",
"2. Парк Культуры",
"3. Октябрьская",...
],..
}
}
Подскажите пожалуйста куда копать
Ответы (1 шт):
Для начала ответ на вопросы, которые вас волнует больше всего:
Почему они повторяются, почему в каждой линии только по одной станции и почему они одинаковые.
"Калининско-Солнцевская линия":[
"35. Подольск"
],
"Арбатско-Покровская линия":[
"35. Подольск"
]
Отвечаю:
Это происходит в данном блоке кода
for (Element lines : doc.select("p.single-station")){
JSONArray linesName = new JSONArray();
String Lines = lines.text();
String Name = stations.text();
linesName.put(Lines);
list.put(Name, linesName);
}
Дело в том, что вы создаете список станций, каждый раз когда вы обрабатываете параграф с названием станции. На странице порядка 350 станций: и для каждой из них вы создаете список, и каждую из них вы кладете в этот вновьсозданный список, и на каждой станции вы берете этот список из одного элемента и кладете его в список линий метро, перезаписывая тем самым ранее вставленные данные... каждый раз.
Именно поэтому в списке станций каждой линии числится только одна станция, которая является самой последней станцией, обработанной вами...эдакий Дункан Маклауд среди станций. Она перезаписала все предыдущие станции и осталась одна.
А повторяется она, потому при обработке списка линий вы получаете не станции, которые принадлежат данной линии, а все станции на странице.
Соответственно, вложенного списка здесь быть не должно
for (Element stations : doc.select("span.js-metro-line.t-metrostation-list-header.t-icon-metroln")) {
for (Element lines : doc.select("p.single-station")){
// ...
}
}
потому что в верстке название линии и список станции не являются вложенными элементами, а идут друг за другом.
<div class="js-toggle-depend s-depend-control-single s-depend-control-active" data-depend="{'toggle-slide':'lines-1'}">
<span class="js-metro-line t-metrostation-list-header t-icon-metroln ln-1" data-line="1">
Сокольническая линия
</span>
</div>
<div class="js-depend s-depend-active" data-depend-set="lines-1">
<div class="js-metro-stations t-metrostation-list-table" data-line="1" style="grid-template-rows: repeat(13,36px);">
<p class="single-station">
<span class="num">
1.
</span>
<span class="name">
Бульвар Рокоссовского
</span>
<span class="t-icon-metroln ln-14" title="переход на станцию «Бульвар Рокоссовского» МЦК">
</span>
</p>
<!-- ... -->
</div>
</div>
Отсюда возникает сложность в том, как связать одно с другим (названия линий с названиями станций)
Если присмотреться внимательнее, то можно заметить
<span class="..." data-line="1">Сокольническая линия</span>
и
<div class="..." data-depend-set="lines-1">
Другими словами у данных линий есть идентификаторы, которые в названии указываются в атрибуте data-line, а в списке линий находится в атрибуте data-depend-set (только в этом случае она еще и дополняется префиксом lines-)
Соответственно их можно связать по данному идентификатору.
Проще будет извлекать элементы со списком станций и для каждой из них находить название линии. А потом уже в данном элементе находить сами станции и добавлять их в список.
Jsoup позволяет искать элементы по значению атрибута с помощью метода getElementsByAttributeValue()
Итого
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CreateJson {
public static String createMap(String resultMap) throws Exception {
Document doc = Jsoup.connect("https://skillbox-java.github.io/").get();
JSONObject root = new JSONObject();
JSONObject list = new JSONObject();
for (Element linesWrapper : doc.select(".js-depend")) {
String lineNumber = linesWrapper.attr("data-depend-set").substring(6);
String lineName = doc.getElementsByAttributeValue("data-line",lineNumber).get(0).text();
JSONArray stations = new JSONArray();
for (Element stationElement : linesWrapper.select(".single-station")) {
stations.put(stationElement.text());
}
list.put(lineName, stations);
}
root.put("stations", list);
Files.write(Paths.get(resultMap), root.toString().getBytes(StandardCharsets.UTF_8));
return root.toString();
}
}
результат:
{
"stations": {
"Калининско-Солнцевская линия": [
"1. Новокосино",
"2. Новогиреево",
"3. Перово",
"4. Шоссе Энтузиастов",
"5. Авиамоторная",
"6. Площадь Ильича",
"7. Марксистская",
"8. Третьяковская",
"9. Деловой центр",
"10. Парк Победы",
"11. Минская",
"12. Ломоносовский проспект",
"13. Раменки",
"14. Мичуринский проспект",
"15. Озёрная",
"16. Говорово",
"17. Солнцево",
"18. Боровское шоссе",
"19. Новопеределкино",
"20. Рассказовка"
],
"Арбатско-Покровская линия": [
"1. Пятницкое шоссе",
"2. Митино",
"3. Волоколамская",
"4. Мякинино",
"5. Строгино",
"6. Крылатское",
"7. Молодежная",
"8. Кунцевская",
"9. Славянский бульвар",
"10. Парк Победы",
"11. Киевская",
"12. Смоленская",
"13. Арбатская",
"14. Площадь Революции",
"15. Курская",
"16. Бауманская",
"17. Электрозаводская",
"18. Семеновская",
"19. Партизанская",
"20. Измайловская",
"21. Первомайская",
"22. Щелковская"
],
"Кольцевая линия": [
"1. Киевская",
"2. Парк Культуры",
"3. Октябрьская",
"4. Добрынинская",
"5. Павелецкая",
"6. Таганская",
"7. Курская",
"8. Комсомольская",
"9. Проспект Мира",
"10. Новослободская",
"11. Белорусская",
"12. Краснопресненская"
],
"Таганско-Краснопресненская линия": [
"1. Котельники",
"2. Жулебино",
"3. Лермонтовский проспект",
"4. Выхино",
"5. Рязанский проспект",
"6. Кузьминки",
"7. Текстильщики",
"8. Волгоградский проспект",
"9. Пролетарская",
"10. Таганская",
"11. Китай-город",
"12. Кузнецкий мост",
"13. Пушкинская",
"14. Баррикадная",
"15. Улица 1905 года",
"16. Беговая",
"17. Полежаевская",
"18. Октябрьское Поле",
"19. Щукинская",
"20. Спартак",
"21. Тушинская",
"22. Сходненская",
"23. Планерная"
],
"Замоскворецкая линия": [
"1. Ховрино",
"2. Беломорская",
"3. Речной вокзал",
"4. Водный стадион",
"5. Войковская",
"6. Сокол",
"7. Аэропорт",
"8. Динамо",
"9. Белорусская",
"10. Маяковская",
"11. Тверская",
"12. Театральная",
"13. Новокузнецкая",
"14. Павелецкая",
"15. Автозаводская",
"16. Технопарк",
"17. Коломенская",
"18. Каширская",
"19. Кантемировская",
"20. Царицыно",
"21. Орехово",
"22. Домодедовская",
"23. Красногвардейская",
"24. Алма-Атинская"
],
"Бутовская линия": [
"1. Битцевский парк",
"2. Лесопарковая",
"3. Улица Старокачаловская",
"4. Улица Скобелевская",
"5. Бульвар адмирала Ушакова",
"6. Улица Горчакова",
"7. Бунинская Аллея"
],
"Люблинско-Дмитровская линия": [
"1. Зябликово",
"2. Шипиловская",
"3. Борисово",
"4. Марьино",
"5. Братиславская",
"6. Люблино",
"7. Волжская",
"8. Печатники",
"9. Кожуховская",
"10. Дубровка",
"11. Крестьянская застава",
"12. Римская",
"13. Чкаловская",
"14. Сретенский бульвар",
"15. Трубная",
"16. Достоевская",
"17. Марьина роща",
"18. Бутырская",
"19. Фонвизинская",
"20. Петровско-Разумовская",
"21. Окружная",
"22. Верхние Лихоборы",
"23. Селигерская"
],
"Большая Кольцевая Линия": [
"1. Савёловская",
"2. Петровский парк",
"3. ЦСКА",
"4. Хорошёвская",
"5. Шелепиха",
"6. Деловой центр"
],
"Некрасовская линия": [
"1. Электрозаводская",
"2. Лефортово",
"3. Авиамоторная",
"4. Нижегородская",
"5. Стахановская",
"6. Окская",
"7. Юго-Восточная",
"8. Косино",
"9. Улица Дмитриевского",
"10. Лухмановская",
"11. Некрасовка"
],
"МЦД-1": [
"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. Лобня"
],
"МЦД-2": [
"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. Подольск"
],
"Каховская линия": [
"1. Каховская",
"2. Варшавская",
"3. Каширская"
],
"Сокольническая линия": [
"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. Коммунарка"
],
"Серпуховско-Тимирязевская линия": [
"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. Алтуфьево"
],
"Филевская линия": [
"1. Александровский сад",
"2. Арбатская",
"3. Смоленская",
"4. Киевская",
"5. Студенческая",
"6. Кутузовская",
"7. Фили",
"8. Багратионовская",
"9. Филевский парк",
"10. Пионерская",
"11. Кунцевская",
"12. Выставочная",
"13. Международная"
],
"Центральное Кольцо": [
"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. Лихоборы"
],
"Калужско-Рижская линия": [
"1. Новоясеневская",
"2. Ясенево",
"3. Теплый стан",
"4. Коньково",
"5. Беляево",
"6. Калужская",
"7. Новые Черёмушки",
"8. Профсоюзная",
"9. Академическая",
"10. Ленинский проспект",
"11. Шаболовская",
"12. Октябрьская",
"13. Третьяковская",
"14. Китай-город",
"15. Тургеневская",
"16. Сухаревская",
"17. Проспект Мира",
"18. Рижская",
"19. Алексеевская",
"20. ВДНХ",
"21. Ботанический сад",
"22. Свиблово",
"23. Бабушкинская",
"24. Медведково"
]
}
}