网络爬虫也叫网络机器人, 是一种可以按照一定规则自动采集互联网信息的程序或脚本, 爬虫一般分为数据采集, 处理, 储存三个部分, 从若干初始网页的URL开始抓取网页, 不断获取页面上的URL放入队列直到满足系统的一定条件停止
JDK1.8
IntelliJ IDEA
DEA自带的Maven
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<!-- HttpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<!--日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
</dependencies>
在 resources 目录下创建 log4j.properties 文件, 并添加以下配置
# A1 在控制台显示日志 log4j.rootLogger=DEBUG,A1 log4j.logger.cn.itcast = DEBUG log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH????ss,SSS} [%t] [%c]-[%p] %m%n
在java的 cn.ayulong.crawler.test 中创建 CrawlerFirst类
package cn.ayulong.crawler.test; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.io.IOException; public class CrawlerFirst { public static void main(String[] args) throws IOException { // 1. 打开浏览器, 创建 HttpClient 对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 2. 输入网址, 发起get请求创建HttpGet对象 HttpGet httpGet = new HttpGet("http://www.baidu.com/"); // 3. 按回车, 发起请求, 返回响应 CloseableHttpResponse response = httpClient.execute(httpGet); // 4. 解析响应, 获取数据 // 判断状态码是否是 200 if (response.getStatusLine().getStatusCode() == 200) { HttpEntity httpEntity = response.getEntity(); String content = EntityUtils.toString(httpEntity, "utf-8"); System.out.println(content); } } } // 直接运行, 成功抓取到百度首页html并打印到控制台
注意: 此方法只能抓取 http 协议的页面, 如果想抓取 https 的页面, 可以参考
HttpClient: Java 的 HTTP 协议客户端, 用于抓取网页数据
public class HttpGetTest { public static void main(String[] args) { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建HttpGet对象, 设置url访问地址 HttpGet httpGet = new HttpGet("http://www.ayulong.cn"); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpGet); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); System.out.println(content.length()); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } } Get请求带参数 public class HttpGetParamTest { public static void main(String[] args) throws Exception { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 设置请求地址是: http://yun.itheima.com/search?keys=Java // 创建URIBuilder URIBuilder uriBuilder = new URIBuilder("http://yun.itheima.com/search"); // 设置参数 uriBuilder.setParameter("keys", "Java"); // 创建HttpGet对象, 设置url访问地址 HttpGet httpGet = new HttpGet(uriBuilder.build()); System.out.println("发起请求的信息: " + httpGet); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpGet); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用 HttpClient 发送不带参数的 post 请求与 发送不带参数的 get 请求类似, 只是 HttpGet 要改为 HttpPost, 所以只记录带参数的 post 请求方式
public class HttpPostParamTest { public static void main(String[] args) throws Exception { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建HttpPost对象, 设置url访问地址 HttpPost httpPost = new HttpPost("http://yun.itheima.com/search"); // 声明List集合, 封装表单中的参数 ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("keys", "Java")); // 创建表单的Entity对象, 第一个参数就是封装好的表单数据, 第二个参数就是编码 UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "utf8"); // 设置表单的Entity对象到 Post 请求中 httpPost.setEntity(formEntity); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpPost); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); System.out.println(content.length()); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public class HttpClientPoolTest { public static void main(String[] args) { // 创建连接池管理器 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); // 设置连接数 cm.setMaxTotal(100); // 设置每个主机的最大连接数 cm.setDefaultMaxPerRoute(10); // 使用连接池管理器发起请求 doGet(cm); doGet(cm); } private static void doGet(PoolingHttpClientConnectionManager cm) { // 不是每次创建新的HttpClient, 而是从连接池中获取 HttpClient 对象 CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); HttpGet httpGet = new HttpGet("http://www.itcast.cn"); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpGet); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); System.out.println(content.length()); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response if (response != null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } // 不能关闭 HttpClient, 由连接池管理 HttpClient // httpClient. close(); } } } }
public class HttpConfigTest { public static void main(String[] args) { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建HttpGet对象, 设置url访问地址 HttpGet httpGet = new HttpGet("http://yun.itheima.com/search?keys=Java"); // 配置请求信息 RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间, 单位是毫秒 .setConnectionRequestTimeout(500) // 设置获取连接的最长时间, 单位是毫秒 .setSocketTimeout(10 * 1000) // 设置数据传输的最长时间, 单位是毫秒 .build(); // 给请求设置请求信息 httpGet.setConfig(config); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpGet); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); System.out.println(content.length()); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
jsoup的主要功能如下:
从一个URL,文件或字符串中解析HTML;
使用DOM或CSS选择器来查找、取出数据;
可操作HTML元素、属性、文本;( Jsoup一般用于解析爬到的数据并存储, 很少用到操作 )
先在pom中导入依赖, 搭建开发环境
public class HttpConfigTest { public static void main(String[] args) { // 创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建HttpGet对象, 设置url访问地址 HttpGet httpGet = new HttpGet("http://yun.itheima.com/search?keys=Java"); // 配置请求信息 RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间, 单位是毫秒 .setConnectionRequestTimeout(500) // 设置获取连接的最长时间, 单位是毫秒 .setSocketTimeout(10 * 1000) // 设置数据传输的最长时间, 单位是毫秒 .build(); // 给请求设置请求信息 httpGet.setConfig(config); CloseableHttpResponse response = null; try { // 使用 HttpClient 发起请求, 获取 response response = httpClient.execute(httpGet); // 解析响应 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "utf8"); System.out.println(content.length()); } } catch(IOException e) { e.printStackTrace(); } finally { // 关闭 response try { response.close(); httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
Jsoup可以直接输入url,它会发起请求并获取数据,封装为Document对象
public class JsoupFirstTest { @Test public void testUrl() throws Exception { // 解析url地址, 第一个参数是访问的url, 第二个参数时访问时候的超时时间 Document doc = Jsoup.parse(new URL("http://www.itcast.cn"), 1000); // 使用标签选择器, 获取title标签中的内容 String title = doc.getElementsByTag("title").first().text(); // 打印 System.out.println(title); } }
PS:虽然使用Jsoup可以替代HttpClient直接发起请求解析数据,但是往往不会这样用,因为实际的开发过程中,需要使用到多线程,连接池,代理等等方式,而jsoup对这些的支持并不是很好,所以我们一般把jsoup仅仅作为Html解析工具使用
@Test public void testString() throws Exception { // 使用工具类读取文件, 获取字符串 String content = FileUtils.readFileToString(new File("D:\\360MoveData\\Users\\Administrator\\Desktop\\test.html"), "utf8"); // 解析字符串 Document doc = Jsoup.parse(content); String title = doc.getElementsByTag("title").first().text(); System.out.println(title); } }
@Test public void testFile() throws Exception { // 解析文件 Document doc = Jsoup.parse(new File("D:\\360MoveData\\Users\\Administrator\\Desktop\\test.html"), "utf8"); String title = doc.getElementsByTag("title").first().text(); System.out.println(title); }
@Test public void testDom() throws Exception { // 解析文件件, 获取Document对象 Document doc = Jsoup.parse(new File("D:\\360MoveData\\Users\\Administrator\\Desktop\\test.html"), "utf8"); // 1.根据id查询元素getElementById Element element = doc.getElementById("city_bj"); // 2.根据标签获取元素getElementsByTag Elements spans = doc.getElementsByTag("span"); // 3.根据class获取元素getElementsByClass Element a = doc.getElementsByClass("class_a class_b").first(); // 4.根据属性获取元素getElementsByAttribute Element abc = doc.getElementsByAttribute("abc").first(); // 5.根据属性与属性值筛选 Element href = doc.getElementsByAttributeValue("href", "http://sh.itcast.cn").first(); // 打印元素内容 System.out.println("获取到的元素内容是: " + element.text()); for (Element span : spans) { System.out.println(span.text()); } System.out.println(a.text()); System.out.println("abc.text() = " + abc.text()); System.out.println("href.text() = " + href.text()); }
@Test public void testSelector2() throws Exception { // 解析html文件, 获取Document对象 Document doc = Jsoup.parse(new File("D:\\360MoveData\\Users\\Administrator\\Desktop\\test.html"), "utf8"); //el#id: 元素+ID,比如: h3#city_bj //Element element = doc.select("h3#city_bj").first(); //el.class: 元素+class,比如: li.class_a //Element element = doc.select("li.class_a").first(); //el[attr]: 元素+属性名,比如: span[abc] //Element element = doc.select("span[abc]").first(); //任意组合: 比如:span[abc].s_name Element element = doc.select("span[abc].s_name").first(); //ancestor child: 查找某个元素下子元素,比如:.city_con li 查找"city_con"下的所有li //Elements elements = doc.select(".city_con li"); //parent > child: 查找某个父元素下的直接子元素,比如: // .city_con > ul > li 查找city_con第一级(直接子元素)的ul,再找所有ul下的第一级li //Elements elements = doc.select(".city_con > ul > li"); //parent > *: 查找某个父元素下所有直接子元素 Elements elements = doc.select(".city_con > ul > *"); // 打印
原文:https://www.cnblogs.com/javaandpython/p/14359020.html