JAVA之HttpClient+Jsoup实现代理IP爬虫
文章目錄:
- HttpClient(請求數據):
- Jsoup解析篩選數據:
- 通過httpclient+jsoup爬取代理ip網址上面的ip和端口,并存入數據庫:
- 篩選數據庫中的有效代理IP,并實現代理IP訪問:
- 我的目錄結構(service接口和實現層省略了沒有貼出來):
- 下面上幾張效果圖:
HttpClient(請求數據):
創建httpclient(介紹兩種方式):
方式一:
方式二(使用連接池獲取httpclient):
//創建連接池管理器PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();//設置最大連接數cm.setMaxTotal(200);//設置訪問每個網站得最大連接數,不影響其它網站得訪問cm.setDefaultMaxPerRoute(20);//返回httpclientreturn HttpClients.custom().setConnectionManager(cm).build();生成URI(控制臺打印出來可以看到是自動生成?來連接參數):
URIBuilder uriBuilder = new URIBuilder("http://www.baidu.com/s").// 設置參數setParameter("ie", "utf-8").// 第一個參數setParameter("f", "8").// 第二個參數setParameter("wd", "test");// 第三個參數URI uri = uriBuilder.build();聲明請求方式get/post(傳入String類型參數,可以直接放入自己拼接的字符串URL):
HttpGet httpGet = new HttpGet(uri); HttpPost httpPost = new HttpPost("https://www.xicidaili.com/nn/" + id);配置請求參數以及代理IP:
// 代理IP設置,代理 ip查詢地址:https://www.xicidaili.com/HttpHost httoHost = new HttpHost("118.181.226.166",44640);// 配置請求參數RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(3000).// 3秒,重連接池獲取連接最長時間setConnectTimeout(5000).// 創建連接最長時間setSocketTimeout(20 * 1000).// 20秒,數據傳輸最長時間// setProxy(httoHost).// 設置代理build();httpGet.setConfig(config);設置用戶代理信息:
httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363");使用httpclient發起請求,判斷狀態碼,并獲取數據:
CloseableHttpResponse response = httpclient.execute(httpGet);// 判斷狀態碼是否為200if (response.getStatusLine().getStatusCode() == 200) {// 獲取響應數據HttpEntity entity = response.getEntity();String string = EntityUtils.toString(entity, "UTF-8");// 存入本地FileUtils.writeStringToFile(new File("C:/Users/17210/Desktop/test2.html"), string, "utf-8");}response.close();httpclient.close();Jsoup解析篩選數據:
注:jsoup也能實現請求,但是不大好使,下面舉個例子
//第一個參數為URL類型,第二個應該是超時時間 Document dom = Jsoup.parse(url, timeoutMillis);用jsoup讀取本地html,并獲取需要的內容:
注:之所以前面存入本地是為了方便查看返回的html結構,以此來尋找特征篩選需要的內容
方式一(不如方式二好使,看看就行):
方式二,通過選擇器的cssquery查找:
//通過標簽名選擇獲取元素,對獲取到的元素操作同上Elements Tagname = dom.select("title");String text = Tagname.first().text();//名命空間查找:c|if查找<c:if>String text2 = dom.select("c|if").first().text();//#id查找String text3 = dom.select("#foot").text();//.class查找String className = dom.select(".feedback").get(2).className();//[attribute]屬性名查找String text4 = dom.select("[onclick]").get(2).text();//[attr=value]屬性值查找String text5 = dom.select("[οnclick=return false;]").first().text();//選擇器組合使用(可以多個任意組合)//元素+ID,如div#titleString text6 = dom.select("div#title").text();//元素+class的名字,如a.feedbackString text7 = dom.select("a.feedback").text();//元素+[屬性名],如a[onclick]String text8 = dom.select("a[onclick]").text();//查找指定元素的全部指定子元素,ancestor child,中間空格隔開String texts = dom.select("div#title a").text();//查找指定元素的指定直接子元素-----下一級中的元素,>兩邊有空格String texts1 = dom.select("div#title > a").text();//查找指定元素的全部直接子元素-----下一級中的元素,>兩邊有空格String texts2 = dom.select("div#title > *").text();通過httpclient+jsoup爬取代理ip網址上面的ip和端口,并存入數據庫:
最近學到了springboot和mybatis于是就用這個框架去實現了。
請求的地址:“https://www.xicidaili.com/nn/” + id
id為網站分頁顯示的頁碼,也是方法傳入的參數。
創建實體,用來存放ip和port:
@Component public class IpAndPort {private int id;private String ip;private int port; /** 這里是get和set方法 **/ }篩選html中的ip和port并存入數據庫:
@Component public class DataAnalysis {@Resourceprivate IpAndPortMapper andPortMapper;@Resourceprivate IpAndPort andPort;public void GetIP() throws IOException { String html = FileUtils.readFileToString(new File("C:/Users/17210/Desktop/test2.html"), "utf-8");Document dom = Jsoup.parse(html); for(org.jsoup.nodes.Element el:dom.select("img[alt=Cn][src]")) {String ip = el.parent().nextElementSibling().text();String port = el.parent().nextElementSibling().nextElementSibling().text();int port2=Integer.valueOf(port).intValue();//將字符串port變成intandPort.setIp(ip);andPort.setPort(port2);andPortMapper.save(andPort);//調用save方法存入數據庫System.out.println("ip地址為:"+ip+"port為"+port2+"------保存至數據庫成功");}}}mapper和mapper.xml(采用mapper動態代理,無需手動實現接口):
@Repository //@Mapper // 表明當前接口是一個Mapper,被Mybatis框架掃描,也在springboot配置自動掃描,就不用在這里聲明了。 public interface IpAndPortMapper {List<IpAndPort> findAll();IpAndPort findById(Integer id);void save(IpAndPort ipAndPort);void update(IpAndPort ipAndPort);void delete(Integer id); } <mapper namespace="cu.ip.port.mapper.IpAndPortMapper">//注意這里的namespace是匹配的接口,別錯了<select id="findAll" resultType="ipAndPort">select * from ip_port</select><select id="findById" parameterType="Int" resultType="ipAndPort">select * from ip_port where id=#{id}</select><insert id="save" parameterType="ipAndPort">INSERT into ip_port(ip,port) VALUES (#{ip},#{port})</insert><update id="update" parameterType="ipAndPort">update ip_port setip=#{ip},port=#{port}where id=#{id}</update><delete id="delete" parameterType="Int">delete from ip_port whereid=#{id}</delete>配置application.properties:
#數據庫MySQL spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.password=root spring.datasource.username=root spring.datasource.url=jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC #Mybatis #掃描--實體,而不是mapper接口 mybatis.type-aliases-package=cu.ip.port.entity #掃描.xml mybatis.mapper-locations=classpath:mapper/*Mapper.xml篩選數據庫中的有效代理IP,并實現代理IP訪問:
注:主要思路,捕獲連接超時異常,然后迭代調用當前方法,傳入的參數變為id+1去數據庫查找下一條有效信息
@Component public class DataCapture {@Resourceprivate IpAndPortService andPortService; public HttpGet httpGet = new HttpGet("https://www.xicidaili.com/nn/");@Resourcepublic IpAndPort proxy;public String ip;public int port;public void dataCaptureWithProxy(int id) {// 使用連接池獲取httpclientCloseableHttpClient httpclient = PoolManager.GetHpptClient();proxy = andPortService.findById(id);ip = proxy.getIp();port = proxy.getPort();HttpHost httoHost = new HttpHost(ip, port);// 配置請求參數RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(3000).// 3秒,重連接池獲取連接最長時間setConnectTimeout(10000)//創建連接最長時間setSocketTimeout(10 * 1000).// 210秒,數據傳輸最長時間setProxy(httoHost).// 設置代理build();httpGet.setConfig(config);// 設置用戶代理信息httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363");// 使用httpclient發起請求,獲得responsetry {CloseableHttpResponse response = httpclient.execute(httpGet);if (response.getStatusLine().getStatusCode() == 200) {System.out.println("有效代理IP,IP地址為:" + ip + "端口號為:" + port);//這里可以繼續迭代,對有效代理做其他處理dataCaptureWithProxy(id + 1);}response.close();httpclient.close();} catch (SocketTimeoutException | ConnectTimeoutException ex) {System.out.println("請求連接超時"+ "當前id為:"+id);dataCaptureWithProxy(id + 1);} catch (Exception ex) {System.out.println("請求異常,異常信息:" + ex.getMessage() + ","+ "當前id為:"+id+"正在嘗試下一條IP");dataCaptureWithProxy(id + 1);//這里開始迭代}}controller中的方法介紹:
@Controller //@ResetController相當于加了個@response,返回文本內容而不是jsp跳轉 public class IpAndPortController {@Resourceprivate IpAndPortService andPortService;@Resourceprivate DataAnalysis da;@Resourceprivate DataCapture ca;//將數據庫中的全部ip和port輸出到瀏覽器頁面 @GetMapping("/findAll")@ResponseBodypublic List<IpAndPort> findAll() {return andPortService.findAll();}//查詢單條記錄@GetMapping("/findById/{id}")public IpAndPort findById(@PathVariable("id") Integer id) {return andPortService.findById(id);} //刪除單條記錄 @GetMapping("/delete/{id}")public void delete(@PathVariable("id") Integer id) {andPortService.delete(id);}//這個方法需要post請求,并將表單傳入的參數映射成對象@PostMapping("/update")public void update(@RequestBody IpAndPort IpAndPort) {andPortService.update(IpAndPort);}//這個方法執行數據插入方法,即將桌面剛剛存入的html進行篩選并存入數據庫,//當定頁面獲取到的數據正常后可以在前面將獲取到的數據進行直接篩選保存@GetMapping("/do")@ResponseBodypublic String statrt() {try {da.GetIP();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return "數據插入數據庫成功!";}//這個方法執行數據抓取,并存入桌面,當肯定抓取到的數據沒有問題時可以省略,在前面改為直接篩選并存入數據庫@GetMapping("/find/{id}")@ResponseBodypublic String findip(@PathVariable("id") String id) throws Exception {try {ca.dataCaputure(id);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return "數據成功復制到桌面!";} //這個方法用于篩選數據庫中有效的IP和port //頁面傳過來的參數為數據庫中查詢的起始地址@GetMapping("/getProxyIp/{id}")@ResponseBodypublic String getProxyIp(@PathVariable("id") int id) throws Exception {ca.dataCaptureWithProxy(id);return "請在控制臺查看查詢結構"}我的目錄結構(service接口和實現層省略了沒有貼出來):
pom.xml依賴—application.properties在上面目錄3中配置mapper代理時貼出來了:
下面上幾張效果圖:
注:本人也是剛開始接觸springboot,代碼有些地方不規范,歡迎指正!
總結
以上是生活随笔為你收集整理的JAVA之HttpClient+Jsoup实现代理IP爬虫的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uniapp 生成html5_uni-a
- 下一篇: 花边新闻获取易语言代码