域名解析是把域名指向網站空間IP,讓人們經過註冊的域名能夠方便地訪問到網站的一種服務;IP地址是網絡上標識站點的數字地址,爲了方便記憶,採用域名來代替IP地址標識站點地址。域名解析就是域名到IP地址的轉換過程,該過程由DNS服務器完成(來自百度百科)html
先來了解兩個知識點java
一、一個域名同一時刻只能對應一個IP地址git
二、一個IP地址能夠解析綁定多個域名,沒有限制github
基於以上知識點,假如咱們已知一個IP地址,咱們怎麼才能獲取解析到該IP地址的全部域名信息呢?一種方式是國家工信部能開放查詢接口以供查詢(不知道會不會開放?);另一種方式就是接下來我要分享的——爬蟲實現:根據IP地址反查域名。web
實現原理其實很簡單,如今已有網站提供了根據IP地址查詢域名的功能,可是須要人爲登陸網站輸入IP地址查詢,我想要實現程序自動化查詢,因此就想到了爬蟲的方式,簡單來講,就是模擬人的查詢行爲,將查詢結果解析成我想要的域名列表。瀏覽器
以site.ip138.com
爲例,打開F12
,輸入一個IP查詢,觀察控制檯請求,看到下圖中信息服務器
請求地址爲:site.ip138.com/119.75.217.…網絡
請求方式爲:GETapp
而後,分析Response,能夠看到,在頁面上看到的綁定域名信息就是下圖紅框中的內容,因此只要能將Response的內容解析出來,獲取到的內容就能夠獲得想要的域名列表。dom
上述Response是HTML頁面,使用jsoup
來解析HTML簡直完美。
jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套很是省力的API,可經過DOM,CSS以及相似於jQuery的操做方法來取出和操做數據。
//解析成Document對象
Document document = Jsoup.parse(result);
if (document == null) {
logger.error("Jsoup parse get document null!");
}
//根據ID屬性「list」獲取元素Element對象(有沒有感受很像jQuery?)
Element listEle = document.getElementById("list");
//根據class屬性和屬性值篩選元素Element集合,並經過eachText()遍歷元素內容
return listEle.getElementsByAttributeValue("target", "_blank").eachText();
複製代碼
result的內容經過HttpClient模擬HTTP請求
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
httpGet.setHeader("Accept-Encoding", "gzip, deflate");
httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
httpGet.setHeader("Cache-Control", "max-age=0");
httpGet.setHeader("Connection", "keep-alive");
httpGet.setHeader("Cookie", "Hm_lvt_d39191a0b09bb1eb023933edaa468cd5=1553090128; BAIDU_SSP_lcr=https://www.baidu.com/link?url=FS0ccst469D77DpdXpcGyJhf7OSTLTyk6VcMEHxT_9_&wd=&eqid=fa0e26f70002e7dd000000065c924649; pgv_pvi=6200530944; pgv_si=s4712839168; Hm_lpvt_d39191a0b09bb1eb023933edaa468cd5=1553093270");
httpGet.setHeader("DNT", "1");
httpGet.setHeader("Host", host);
httpGet.setHeader("Upgrade-Insecure-Requests", "1");
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
String result = HttpUtils.doGet(httpGet);
複製代碼
HTTP請求工具類
public class HttpUtils {
private static Logger logger = LoggerFactory.getLogger(HttpUtils.class);
public static String doGet(HttpGet httpGet) {
CloseableHttpClient httpClient = null;
try {
httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(10000)
.setSocketTimeout(5000).build();
httpGet.setConfig(requestConfig);
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200 ||
httpResponse.getStatusLine().getStatusCode() == 302) {
HttpEntity entity = httpResponse.getEntity();
return EntityUtils.toString(entity, "utf-8");
} else {
logger.error("Request StatusCode={}", httpResponse.getStatusLine().getStatusCode());
}
} catch (Exception e) {
logger.error("Request Exception={}:", e);
} finally {
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
logger.error("關閉httpClient失敗", e);
}
}
}
return null;
}
}
複製代碼
新增Controller
@RestController
public class DomainSpiderController {
private static Logger logger = LoggerFactory.getLogger(DomainSpiderController.class);
@Autowired
private DomainSpiderService domainSpiderService;
/** * @param ip 119.75.217.109 * @return */
@RequestMapping("/spider/{ip}")
@ResponseBody
public List<String> domainSpider(@PathVariable("ip") String ip) {
long startTime = System.currentTimeMillis();
List<String> domains = domainSpiderService.domainSpiderOfIp138(ip);
if(domains == null || domains.size() == 0) {
domains = domainSpiderService.domainSpiderOfAizan(ip);
}
long endTime = System.currentTimeMillis();
logger.info("完成爬蟲任務總耗時:{}s", (endTime - startTime) / 1000);
return domains;
}
}
複製代碼
啓動Spring Boot應用,訪問瀏覽器:http://localhost:8080/spider/119.75.217.109 得到返回結果以下:
怎麼樣?是否是很簡單?
優化改進:有時候僅僅經過一個網站查詢的域名數據可能不太準確,甚至查詢不到數據,咱們也無法判斷誰纔是正確的,因此,能夠經過爬取多個網站的結果結合起來使用,例如:dns.aizhan.com
提出疑問:這些提供根據IP反查域名的網站,是怎麼實現的呢?我諮詢過其餘人,他們的回答是這些網站收集了不少IP和域名的對應關係,真實狀況是這樣的嗎?
代碼已上傳至碼雲
和Github
上,歡迎下載學習