Я разобрал кое-какую архитектуру Java и материалы интервью (микросервисы, кластеры, распределенное, промежуточное ПО и т.д.), а друзья, кому нужно, могут обратить внимание на официальный аккаунт [Внутренние дела Программиста], и получить самостоятельно без всяких рутин
Автор этой статьи:Внутри программатора
Больше избранных статей
- Технологический отдел неожиданно объявил, что все JAVA-разработчики должны знать фреймворк автоматизации тестирования интерфейсов.
- Резюме на 30 000 слов, суть оптимизации Mysql
написать впереди
Из-за эпидемии я работаю удаленно из дома. Бизнес компании идет медленно. Честно говоря, работы не так много. Я ем, сплю, посещаю техническое сообщество и пишу блоги каждый день. Утром я хотел вздремнуть, но вдруг пришло голосовое сообщение от начальника отдела и сообщило мне адрес для подключения.woohoo.stats.gov.talents/stats/его больше нет/он…Меня попросили узнать названия провинций и городов, а также коды городов по всей стране и составить словарную таблицу с ограничением по времени в одно утро.
Разделите потребности
Чтобы построить словарную таблицу для хранения названий провинций и городов по всей стране, дизайн структуры таблицы относительно прост, так что насчет данных о городах?
Есть два решения:
Трудно копировать и вставлять, а сказать можно только несколько сотен.
Напишите сканер раз и навсегда
Но как программист нет ничего, что нельзя было бы решить с помощью программы, хотя работаCtrl+C
,Ctrl+V
Он используется очень часто, и довольно стыдно копировать и вставлять без технического содержания.
рептилии
Исходя из этого требования, мне нужно только название города. Сканер выбирает Jsoup. Jsoup — это анализатор Java HTML, который может напрямую анализировать URL-адрес и текстовое содержимое HTML. Он предоставляет очень простой API для извлечения данных и манипулирования ими с помощью методов манипулирования, подобных DOM, CSS и jQuery.
Jsoup основан на HTML-страницах.<body>
,<td>
,<tr>
и другие теги для получения текстового контента, поэтому сначала проанализируйте структуру целевой страницы. ОткрытымF12
Глядя на структуру страницы, мы обнаружили, что нужные нам целевые данные находятся в пятом<tbody>
Этикеткаclass
собственностьprovincetr
из<tr>
в этикетке.
<tr class="provincetr">
<td>
<a href="11.html">北京市<br></a>
</td>
<td>
<a href="12.html">天津市<br>
</td>
.........
</tr>
получить его снова<td>
на этикетке<a>
Атрибута метки достаточно, название провинции найдено, а дальше смотрим, где находится название города, соответствующее провинции, атрибутhref="11.html"
Это соответствующая страница города под провинцией.Url
http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2018/11.html
Поиск названия города аналогичен описанному выше процессу анализа, поэтому я не буду повторять его здесь.Теперь, когда местоположение данных определено, начнется конкретная работа по сканированию.
реализация обходчика
1. Введите зависимости Jsoup
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.7.3</version>
</dependency>
2. Написание кода
Реализация кода относительно проста, способов всего два, сложности нет, главное быть внимательным, достаточно очистить вложенную структуру тегов страницы. Шаг за шагом следуйте логике предыдущего анализа
/**
* @author xin
* @description 解析省份
* @date 2019/11/4 19:24
*/
public static void parseProvinceName(Map<String, Map<String, String>> map, String url) throws IOException {
/**
* 获取页面文档数据
*/
Document doc = Jsoup.connect(url).get();
/**
* 获取页面上所有的tbody标签
*/
Elements elements = doc.getElementsByTag("tbody");
/**
* 拿到第五个tbody标签
*/
Element element = elements.get(4);
/**
* 拿到tbody标签下所有的子标签
*/
Elements childrens = element.children();
/**
* 当前页面的URL
*/
String baseUri = element.baseUri();
for (Element element1 : childrens) {
Elements provincetrs = element1.getElementsByClass("provincetr");
for (Element provincetr : provincetrs) {
Elements tds = provincetr.getElementsByTag("td");
for (Element td : tds) {
String provinceName = td.getElementsByTag("a").text();
String href = td.getElementsByTag("a").attr("href");
System.out.println(provinceName + " " + baseUri + "/" + href);
map.put(provinceName, null);
/**
* 组装城市页面的URL,进入城市页面爬城市名称
*/
parseCityName(map, baseUri + "/" + href, provinceName);
}
}
}
}
Одна вещь, которую следует отметить при захвате названия города, название провинции и города муниципального города совпадают.
/**
* @author xin
* @description 解析城市名称
* @date 2019/11/4 19:26
*/
public static void parseCityName(Map<String, Map<String, String>> map, String url, String provinceName) throws IOException {
Document doc = Jsoup.connect(url).get();
Elements elements = doc.getElementsByTag("tbody");
Element element = elements.get(4);
Elements childrens = element.children();
/**
*
*/
String baseUri = element.baseUri();
Map<String, String> cityMap = new HashMap<>();
for (Element element1 : childrens) {
Elements citytrs = element1.getElementsByClass("citytr");
for (Element cityTag : citytrs) {
Elements tds = cityTag.getElementsByTag("td");
/**
* 直辖市,城市名就是本身
*/
String cityName = tds.get(1).getElementsByTag("a").text();
if (cityName.equals("市辖区")) {
cityName = provinceName;
}
String href1 = tds.get(1).getElementsByTag("a").attr("href");
System.out.println(cityName + " " + href1);
cityMap.put(cityName, href1);
}
}
map.put(provinceName, cityMap);
}
public class test2 {
public static void main(String[] args) throws IOException {
Map<String, Map<String, String>> map = new HashMap<>();
parseProvinceName(map, "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2018");
System.out.println(JSON.toJSONString(map));
}
}
3. Выходная строка JSON
В настоящее время, пока требуется название провинции и города, сканер не имеет глубины.Если вам нужна информация, такая как районы и округа, вы можете использовать URL-адрес за городом.35/3508.html
продолжать спускаться вниз
{
"福建省": {
"龙岩市": "35/3508.html",
"南平市": "35/3507.html",
"莆田市": "35/3503.html",
"福州市": "35/3501.html",
"泉州市": "35/3505.html",
"漳州市": "35/3506.html",
"厦门市": "35/3502.html",
"三明市": "35/3504.html",
"宁德市": "35/3509.html"
},
"西藏自治区": {
"拉萨市": "54/5401.html",
"昌都市": "54/5403.html",
"日喀则市": "54/5402.html",
"那曲市": "54/5406.html",
"林芝市": "54/5404.html",
"山南市": "54/5405.html",
"阿里地区": "54/5425.html"
},
"贵州省": {
"贵阳市": "52/5201.html",
"毕节市": "52/5205.html",
"铜仁市": "52/5206.html",
"六盘水市": "52/5202.html",
"遵义市": "52/5203.html",
"黔西南布依族苗族自治州": "52/5223.html",
"安顺市": "52/5204.html",
"黔东南苗族侗族自治州": "52/5226.html",
"黔南布依族苗族自治州": "52/5227.html"
},
"上海市": {
"上海市": "31/3101.html"
},
"湖北省": {
"黄冈市": "42/4211.html",
"孝感市": "42/4209.html",
"恩施土家族苗族自治州": "42/4228.html",
"省直辖县级行政区划": "42/4290.html",
"襄阳市": "42/4206.html",
"鄂州市": "42/4207.html",
"十堰市": "42/4203.html",
"咸宁市": "42/4212.html",
"黄石市": "42/4202.html",
"荆州市": "42/4210.html",
"随州市": "42/4213.html",
"宜昌市": "42/4205.html",
"武汉市": "42/4201.html",
"荆门市": "42/4208.html"
},
"湖南省": {
"湘潭市": "43/4303.html",
"衡阳市": "43/4304.html",
"张家界市": "43/4308.html",
"益阳市": "43/4309.html",
"岳阳市": "43/4306.html",
"娄底市": "43/4313.html",
"株洲市": "43/4302.html",
"常德市": "43/4307.html",
"湘西土家族苗族自治州": "43/4331.html",
"郴州市": "43/4310.html",
"邵阳市": "43/4305.html",
"长沙市": "43/4301.html",
"永州市": "43/4311.html",
"怀化市": "43/4312.html"
},
"广东省": {
"河源市": "44/4416.html",
"韶关市": "44/4402.html",
"茂名市": "44/4409.html",
"汕头市": "44/4405.html",
"清远市": "44/4418.html",
"深圳市": "44/4403.html",
"珠海市": "44/4404.html",
"广州市": "44/4401.html",
"肇庆市": "44/4412.html",
"中山市": "44/4420.html",
"江门市": "44/4407.html",
"云浮市": "44/4453.html",
"惠州市": "44/4413.html",
"湛江市": "44/4408.html",
"东莞市": "44/4419.html",
"揭阳市": "44/4452.html",
"阳江市": "44/4417.html",
"佛山市": "44/4406.html",
"汕尾市": "44/4415.html",
"潮州市": "44/4451.html",
"梅州市": "44/4414.html"
}
.......
}
Данные страницы сканирования Jsoup сильно зависят от сети. Например, мой широкополосный доступ Founder за 500 юаней в год 50M вот-вот зависнет, и в среднем это удается только один раз после трех запусков. Это слишком сложно для меня!
Exception in thread "main" java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1569)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:443)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:465)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:424)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:178)
at org.jsoup.helper.HttpConnection.get(HttpConnection.java:167)
at com.xinzf.project.jsoup.test2.parseProvinceName(test2.java:32)
at com.xinzf.project.jsoup.test2.main(test2.java:17)
Суммировать
От анализа страницы до написания кода может пройти больше времени, чем простое копирование и вставка, но я все же предпочитаю использовать программу для решения проблемы не из-за того, насколько я усерден, а потому, что я ленив.
Сегодня так много нужно сказать, если эта статья была вам полезна, я надеюсь получить от вас лайк 👍
Ваше одобрение является движущей силой для моего письма!