java爬虫学习记录
HttpClient的使用
使用HttpClient发起get请求
- 请求携带参数直接在url上拼接即可
@Resource
private HttpClient httpClient;
/**
* 演示httpClient发起get请求
* 1.创建httpclient
* 2.创建httpGet
* 3.调用httpclient的execute方法发起请求
* 4.接受response返回值,进行解析
*/
public void get() throws Exception{
//get请求,携带参数直接在url中拼接
String url = "https://itbaima.net/document";
//创建请求对象
HttpGet httpGet = new HttpGet(url);
//执行请求
HttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
System.out.println("请求成功");
HttpEntity entity = response.getEntity();
//使用工具类将响应数据转换为html格式的字符串
String html = EntityUtils.toString(entity, "utf-8");
//打印请求返回的数据
System.out.println(html);
//将数据放到一个文件中
saveToFile(html,"get.html");
//关闭流
response.getEntity().getContent().close();
}else{
System.out.println("请求失败");
}
}
使用HttpClient发起post请求
- 携带参数需要向httpPost对象设置一个HttpEntity,参数保存在HttpEntity中
/**
* 演示发起post请求
* 1.创建HttpPost对象
* 2.使用列表准备参数
* 3.将参数放到一个httpEntity中
* 4.将参数设置到htpPost对象中
* 5.使用HttpClient发起Post请求
* 6.获取响应结果
* 7.打印响应的结果
*/
public void post() throws Exception {
//1.创建httpClient
//2.1创建httpPost
HttpPost httpPost = new HttpPost("https://www.jdcloud.com/cn/search");
//2.2准备参数,?query=java
List<NameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("query","python"));
//将参数放到http实体中
HttpEntity httpEntity = new UrlEncodedFormEntity(form,"utf-8");
httpPost.setEntity(httpEntity);
//3.发起请求
HttpResponse response = httpClient.execute(httpPost);
//4.打印响应的结果
System.out.println("response.getEntity().getContentType() = " + response.getEntity().getContentType());
String html = EntityUtils.toString(response.getEntity(), "utf-8");
saveToFile(html,"post.html");
System.out.println("html = " + html);
}
使用HttpClient连接池管理HttpClient连接
- 需要HttpClient时,直接调用静态方法获取即可
public class HttpClientPool {
//连接池对象
private static PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
public static HttpClient create(){
//创建HttpClient对象放入连接池中管理
return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager).build();
}
}
Jsoup的使用
- 一个解析HTML的工具包
获取解析html文档对象的三种方式
- 使用Jsoup的静态方法parse获取html文档对象
- 通过文件的方式
/**
* 通过File获取要解析的html文档对象
* @throws IOException
*/
public Document create01() throws IOException {
Document document = Jsoup.parse(new File("get.html"));
return document;
}
- 通过html格式字符串的方式
/**
* 通过一个html的字符串获取文档对象
*/
public Document create02(){
Document document = Jsoup.parse("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <link rel=\"icon\" href=\"/favicon.ico\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
" <link rel=\"stylesheet\" href=\"https://lib.baomitu.com/element-plus/2.3.12/index.css\"/>\n" +
" <link rel=\"stylesheet\" href=\"https://lib.baomitu.com/normalize/latest/normalize.css\">\n" +
" <link rel=\"stylesheet\" href=\"https://lib.baomitu.com/font-awesome/6.4.2/css/all.min.css\">\n" +
" <title>柏码 - 让每一行代码都闪耀智慧的光芒!</title>\n" +
" <style>\n" +
" body{\n" +
" margin: 0;\n" +
" font-family: system-ui, -apple-system, \"Segoe UI\",\n" +
" Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\",\n" +
" \"Liberation Sans\", sans-serif, \"Apple Color Emoji\",\n" +
" \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n" +
" }\n" +
"\n" +
" @font-face {\n" +
" font-family: \"Fira Code\";\n" +
" src: url(\"https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/firacode/6.2.0/ttf/FiraCode-Medium.ttf\");\n" +
" }\n" +
" </style>\n" +
" <script type=\"module\" crossorigin src=\"/assets/index-0afa16d6.js\"></script>\n" +
" <link rel=\"stylesheet\" href=\"/assets/index-4cb07b3b.css\">\n" +
" </head>\n" +
" <body style=\"width: 100vh;height: 100vh;overflow:hidden\">\n" +
" <div id=\"app\"></div>\n" +
" \n" +
" </body>\n" +
"</html>");
return document;
}
- 通过url远程获取html的方式
/**
* 通过url获取远程的html文档对象
*/
public Document create03() throws IOException {
String url = "http://baidu.com";
Document document = Jsoup.parse(new URL(url),10000);
return document;
}
解析html文档的方式
- 通过id获取html文档的元素
/**
* 通过元素的id解析
*/
public void parseByElementId() throws IOException {
Document document = create01();
Element element = document.getElementById("app");
System.out.println("element = " + element);
}
- 通过元素className获取
/**
* 通过元素的类名解析
* @throws IOException
*/
public void parseByElementClassName() throws IOException {
Document document = create01();
Elements elements = document.getElementsByClass("test2");
for (Element element : elements) {
System.out.println("element = " + element.text());
}
}
- 通过元素的属性获取
/**
* 通过元素的属性解析
* @throws IOException
*/
public void parseByElementAttribute() throws IOException {
Document document = create01();
Elements elements = document.getElementsByAttribute("style");
for (Element element : elements) {
System.out.println("element = " + element.text());
}
}
- 通过元素的属性和属性值组合获取
/**
* 通过元素的属性和属性值解析
* @throws IOException
*/
public void parseByElementAttributeAndValue() throws IOException {
Document document = create01();
Elements elements = document.getElementsByAttributeValue("width", "100px");
for (Element element : elements) {
System.out.println("element = " + element);
}
}
- 通过css选择器的方式获取元素
- 使用方式与jquery的方式类似
/**
* 通过CSS选择器进行解析,操作方式与jquery类似
*/
public void parseByCSSSelector01() throws IOException {
Document document = create01();
Elements body = document.select("body");
for (Element element : body) {
System.out.println("element = " + element);
}
}
- 通过css选择器组合的方式获取元素
/**
* 通过CSS选择器组合进行解析
*/
public void parseByCSSSelector02() throws IOException {
Document document = create01();
Elements elements = document.select("body div[class=test2]");
for (Element element : elements) {
System.out.println("element = " + element);
}
}
- 获取元素标签内的值使用text()方法
/**
* 获取元素标签内的文本
* @throws IOException
*/
public void getText() throws IOException {
Document document = create01();
String text = document.select("main").text();
System.out.println("text = " + text);
}
- 获取元素属性的值使用attr()方法
/**
* 获取元素标签属性的值
* @throws IOException
*/
public void getAttributeValue() throws IOException {
Document document = create01();
String attribute = document.select("main").attr("width");
System.out.println("attribute = " + attribute);
}
使用HttpClient和Jsoup爬虫广科官网的综合案例
- 抓取广科官网的页面,解析图片的url
public void test() throws IOException {
String url = "https://www.gdit.edu.cn/main.htm";
HttpClient httpClient = HttpClientPool.create();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
String html = EntityUtils.toString(response.getEntity(), "utf-8");
saveToFile(html,"lwj.html");
Document document = Jsoup.parse(html);
Elements elements = document.select("img");
int count = 0;
for (Element element : elements) {
//System.out.println("element = " + element);
String src = element.attr("src");
System.out.println("src = " + src);
Pattern pattern = Pattern.compile("^/_upload.*");
//下载图片
if (pattern.matcher(src).matches()) {
System.out.println(++count);
downloadImage(src,count+"");
}
}
}
- 下载图片,拼接url下载图片
public void downloadImage(String src,String filename) throws IOException {
src = "https://www.gdit.edu.cn/" + src;
HttpGet httpGet = new HttpGet(src);
HttpResponse response = HttpClientPool.create().execute(httpGet);
//写入文件
response.getEntity().writeTo(new FileOutputStream("./imgs/"+filename+src.substring(src.lastIndexOf('.'))));
}
WebMagic的使用
- 四个核心组件
- Downloader:页面下载器,用获取页面
- PageProcessor:页面解析器,用于解析页面
- Scheduler:Url链接地管理器,用管理爬取的url地址,url去重等等
- Pipeline:数据持久器,用将数据保存到数据库或者保存的文件中,默认打印到控制台
- Spider:爬虫的控制引擎,用启动爬虫
- 依赖包
<!--引入WebMagic依赖-->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
</dependency>
PageProcessor组件的使用
-
获取html对象,解析html对象的方式,Selectable接口提供了多种解析获取元素的方式
- 获取html的文档对象,使用jsoup的方式进行解析
/** * 解析html对象的方式一 * 使用jsoup解析 * @param html */ public void parse01(Html html){ Document document = html.getDocument(); Element element = document.getElementById("main"); System.out.println("element = " + element); }
- 使用css选择器解析
/** * 解析方式二 * 使用css选择器解析 * @param html */ public void parse02(Html html){ //使用css选择器解析,可以使用css()方法,也可以使用$()方法,两者等价 Selectable selectable = html.css("#mian"); //使用get()方法获取文本信息 System.out.println("selectable = " + selectable.get()); }
- 使用xpath解析
/** * 解析方式三 * 使用xpath解析 * @param html */ public void parse03(Html html){ Selectable xpath = html.xpath("/div"); System.out.println("xpath.get() = " + xpath.get()); }
- 使用正则表达式解析
/** * 解析方式四 * 使用正则表达式解析 * @param html */ public void parse04(Html html){ Selectable regex = html.regex("^<img>$"); System.out.println("regex = " + regex); }
-
自定义页面解析器,解析实习僧的页面
@Component
public class PageProcessorDemo implements PageProcessor {
@Autowired
private Site site;
@Override
public void process(Page page) {
Html html = page.getHtml();
//尝试获取职位名称的节点,如果存在说明是职位详情页,否则就是职位列表页
List<Selectable> nodes = html.$("div.new_job_name","text").nodes();
if (nodes.size() > 0){
//职位详情页
//职位名称
String positionName = html.css("div.new_job_name>span","text").get();
//最低日薪和最高日薪
String salary = html.css("div.job_msg > span.job_money.cutom_font","text").get();
int[] salary1 = getSalary(salary);
Integer minSalary = salary1[0],maxSalary = salary1[1];
//学历要求
String edu = html.css("div.job_msg > span.job_academic","text").get();
//工作地点
String city = html.css("div.job_msg > span.job_position","text").get();
//工作周期
String cycle = html.css("div.job_msg > span.job_week.cutom_font","text").get();
//实习时长
String duration = html.css("div.job_msg > span:nth-child(5)","text").get();
//职位描述
String describe = html.css("div.job_part > div","text").get();
//职位url
String url = page.getUrl().get();
//公司名称
String companyName = html.css("div.com_intro > a.com-name","text").get();
//公司行业
String profession = "";
//公司规模
String size = "";
//公司性质
String nature = "";
List<String> all = html.css("div.com-detail > div","text").all();
if (all.size()==4){
//公司行业,规模,性质信息都有
profession = all.get(0);
nature = all.get(1);
size = all.get(2);
}else if (all.size()==3){
//有公司规模,性质信息
nature = all.get(0);
size = all.get(1);
}
//封装职位对象
Position position = new Position(null, positionName, minSalary, maxSalary, companyName, city, cycle, duration, url, describe, edu);
//封装公司对象
Company company = new Company(null, companyName, profession, size, null, nature);
//数据持久化
page.putField("position",position);
page.putField("company",company);
}else{
//职位列表页
//获取每个职位的url
List<String> links = html.css("div.clearfix.intern-detail a").links().regex("^https://.*").all();
//将url放入待爬列表中
page.addTargetRequests(links);
//跳过数据持久化
page.setSkip(true);
}
}
@Override
public Site getSite() {
return site;
}
/**
* 处理工资区间
* @param salary
* @return
*/
public int[] getSalary(String salary){
int[] result = new int[2];
salary = salary.substring(0,salary.indexOf('/'));
String[] split = salary.split("-");
if (split.length==2){
result[0] = Integer.valueOf(split[0].trim());
result[1] = Integer.valueOf(split[1].trim());
}else if (split.length==1){
result[0] = Integer.valueOf(split[0].trim());
result[1] = result[0];
}
return result;
}
}
Pipeline的使用
- webMagic提供了三种基础的Pipeline实现类
- ConsolePipeline:默认的持久化组件,将信息输出到控制台
- FilePipeline:将信息保存到文件中
- JsonFilePipeline:将数据按json格式保存到文件中
- 我们也可以实现Pipeline接口进行自定义持久化组件
- 自定义Pipeline持久化数据到数据库
@Component
public class MyPipeline implements Pipeline {
@Autowired
private PositionService positionService;
@Autowired
private CompanyService companyService;
@Override
public void process(ResultItems resultItems, Task task) {
Position position = (Position)resultItems.get("position");
//保存职位信息
positionService.save(position);
Company company = (Company) resultItems.get("company");
//判断公司是否已经保存过
QueryWrapper<Company> companyQueryWrapper = new QueryWrapper<>();
companyQueryWrapper.eq("name",company.getName());
Company one = companyService.getOne(companyQueryWrapper);
if (null == one){
companyService.save(company);
}
}
}
DownLoader页面下载器的使用
void process() {
//创建一个下载器对象
HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
//创建一个代理服务器对象,通过form可以设置多个代理服务器
SimpleProxyProvider proxyProvider = SimpleProxyProvider.from(new Proxy("81.70.187.80", 8080));
//给下载器设置代理服务器对象
httpClientDownloader.setProxyProvider(proxyProvider);
Spider.create(myPageProcessor)
//指定使用代理服务器的下载器
.setDownloader(httpClientDownloader)
.addUrl("https://www.shixiseng.com/intern/inn_klti02rhwo1y?pcm=pc_SearchList")
.run();
}
配合selenium前端自动化测试框架,自定义DownLoader页面下载器,解决页面动态加载的问题
<!--引入selenium依赖 -->
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.8.0</version>
</dependency>
- 下载chrome浏览器驱动,并将驱动加入到环境变量中
- 使用案例:打开京东,输入电脑进行搜索
void chromeTest() throws InterruptedException, IOException {
//创建Chrome的配置信息,设置chrome驱动的位置
System.setProperty("webdriver.chrome.driver","C:\\Users\\杨逸\\AppData\\Local\\chromedriver-win64\\chromedriver.exe");
//解决只允许本地连接的警告:Only local connections are allowed.高版本似乎不允许接受所有远程连接
System.setProperty("webdriver.chrome.whitelistedIps", "127.0.0.1");
//创建一个浏览器配置对象
ChromeOptions chromeOptions = new ChromeOptions();
//设置参数
//开启无头模式
//chromeOptions.addArguments("--headless");
//设置窗口大小
chromeOptions.addArguments("--window-size=1920,1080");
//设置允许所有远程连接
chromeOptions.addArguments("--remote-allow-origins=*");
//设置请求头
chromeOptions.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36");
//创建浏览器驱动对象
ChromeDriver chromeDriver = new ChromeDriver(chromeOptions);
//访问京东
chromeDriver.get("https://www.jd.com");
//添加cookie信息
WebDriver.Options manage = chromeDriver.manage();
Map<String, String> cookie = getCookie();
//manage.deleteAllCookies();
for (Map.Entry<String, String> entry : cookie.entrySet()) {
//注意添加的cookie不能含有空格
manage.addCookie(new Cookie(entry.getKey().trim(), entry.getValue().trim()));
}
//刷新当前页,获取原始对象刷新页面
chromeDriver.navigate().refresh();
//输入信息,
chromeDriver.findElement(By.ByCssSelector.cssSelector("#key")).sendKeys("电脑");
Thread.sleep(1000);
//点击搜索
chromeDriver.findElement(By.cssSelector("#search > div > div.form > button")).click();
Thread.sleep(5000);
//滚动
chromeDriver.executeScript("window.scrollTo(0,document.body.scrollHeight)");
Thread.sleep(5000);
String html = chromeDriver.getPageSource();
System.out.println("html = " + html);
//保存抓取到的页面
FileOutputStream fileOutputStream = new FileOutputStream("selenium.html");
fileOutputStream.write(html.getBytes());
//关闭浏览器
fileOutputStream.close();
chromeDriver.close();
}
- 案例二:爬取实习僧平台上java实习的所有数据
- 涉及窗口的打开和关闭
- 窗口的滚动
package com.yangyi.webMagicDemo.component;
import lombok.SneakyThrows;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.downloader.Downloader;
import us.codecraft.webmagic.selector.PlainText;
import javax.annotation.PreDestroy;
import java.util.*;
/**
* @Projectname: webMgaicDemo
* @Filename: SeleniumDownLoader
* @Author: 杨逸
* @Data:2023/10/15 11:43
* @Description: 配合Selenium的页面下载器
*/
@Component
public class SeleniumDownLoader implements Downloader {
private ChromeDriver chromeDriver;
public SeleniumDownLoader(){
//初始化无头浏览器
//创建Chrome的配置信息,设置chrome驱动的位置
System.setProperty("webdriver.chrome.driver","C:\\Users\\杨逸\\AppData\\Local\\chromedriver-win64\\chromedriver.exe");
//解决只允许本地连接的警告:Only local connections are allowed.高版本似乎不允许接受所有远程连接
System.setProperty("webdriver.chrome.whitelistedIps", "127.0.0.1");
//创建一个浏览器配置对象
ChromeOptions chromeOptions = new ChromeOptions();
//设置参数
//开启无头模式
//chromeOptions.addArguments("--headless");
//设置窗口大小
chromeOptions.addArguments("--window-size=1920,1080");
//设置允许所有远程连接
chromeOptions.addArguments("--remote-allow-origins=*");
//设置请求头
chromeOptions.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36");
//创建浏览器驱动对象
chromeDriver = new ChromeDriver(chromeOptions);
}
@Override
public Page download(Request request, Task task) {
//获取要访问的url
String url = request.getUrl();
chromeDriver.get(url);
//判断是列表页还是详情页
List<WebElement> elements = chromeDriver.findElements(By.cssSelector("div.new_job_name"));
if(elements.size()>0){
//详情页
Page page = createPage(chromeDriver.getPageSource(), chromeDriver.getCurrentUrl());
//获取详情页窗口的句柄
String windowHandleBefore = chromeDriver.getWindowHandle();
//点击进入公司详情页
chromeDriver.findElement(By.cssSelector("#__layout > div > div.intern-detail-page.primary-content.clearfix > div.job-box > div.job-content > div.content_right > div.job-about > div.con-job > div.com_intro > a.com-name")).click();
//获取公司详情页的url,放到header中保存
String companyUrl = chromeDriver.getCurrentUrl();
Map<String,List<String>> headers = new HashMap<>();
headers.put("companyUrl", Arrays.asList(companyUrl));
page.setHeaders(headers);
//获取所有仓库句柄
Set<String> windowHandles = chromeDriver.getWindowHandles();
for (String windowHandle : windowHandles) {
//关闭不是当前窗口的其他窗口
if (!windowHandleBefore.equals(windowHandle)) {
chromeDriver.switchTo().window(windowHandle).close();
chromeDriver.switchTo().window(windowHandleBefore);
}
}
//关闭当前窗口
//chromeDriver.close();
return page;
}
//列表页
Page page = createPage(chromeDriver.getPageSource(), chromeDriver.getCurrentUrl());
//判断是否能翻页
WebElement element = chromeDriver.findElement(By.cssSelector("#__layout > div > div.interns > div.result-list.clearfix > div.primary-content.f-l > div:nth-child(1) > div.pagination-wrap > div > button.btn-next"));
if (element.isEnabled()) {
//下滑到底部
chromeDriver.executeScript("window.scrollTo(0,document.body.scrollHeight)");
System.out.println("element = " + element);
//点击翻页,获取下一页的url
element.click();
page.addTargetRequest(new Request(chromeDriver.getCurrentUrl()));
}
return page;
}
@Override
public void setThread(int i) {
}
/**
*
* @param html 页面
* @param url 页面的URL
* @return
*/
private Page createPage(String html,String url){
Page page = new Page();
//设置页面原生文本信息
page.setRawText(html);
//设置页面的URL信息
page.setUrl(new PlainText(url));
//设置Request对象
page.setRequest(new Request(url));
//设置抓取成功标志
page.setDownloadSuccess(true);
return page;
}
@PreDestroy
public void destroy(){
chromeDriver.quit();
}
}
Scheluder URl队列管理器的使用
- 没有特殊需求使用默认的即可
- 作用:
- 对待抓取的URL队列进行管理
- 对已抓取的URL进行去重
- 对url进行管理的类
类 | 说明 | 备注 |
---|---|---|
DuplicateRemovedScheduler | 抽象基类,提供一些模板方法 | 继承它可以实现自己的功能 |
QueueScheduler | 使用内存队列保存待抓取URL | 默认管理url使用的队列管理器 |
PriorityScheduler | 使用带有优先级的内存队列保存待抓取URL | 耗费内存较QueueScheduler更大,但是当设置了request.priority之后,只能使用PriorityScheduler才可使优先级生效 |
FileCacheQueueScheduler | 使用文件保存抓取URL,可以在关闭程序并下次启动时,从之前抓取到的URL继续抓取 | 需指定路径,会建立.urls.txt和.cursor.txt两个文件 |
RedisScheduler | 使用Redis保存抓取队列,可进行多台机器同时合作抓取 | 需要安装并启动redis |
- 对url进行去重的类
- 默认使用HashSetDuplicateRemover进行去重
类 | 说明 |
---|---|
HashSetDuplicateRemover | 使用HashSet来进行去重,占用内存较大 |
BloomFilterDuplicateRemover | 使用BloomFilter来进行去重,占用内存较小,但是可能漏抓页面 |
- 演示使用布隆过滤器BloomFilterDuplicateRemover进行url过滤
@RequestMapping("/start")
public String start(){
//初始化抓取的url
String baseUrl = "https://www.shixiseng.com/interns?type=intern&keyword=java&area&months&days°ree&official&enterprise&salary=-0&publishTime&sortType&city=%E5%85%A8%E5%9B%BD&page=";
List<String> urls = new ArrayList<>();
for (int i = 1; i <= 11; i++) {
urls.add(baseUrl+i);
}
//创建配置url管理器,设置url去重策略
QueueScheduler queueScheduler = new QueueScheduler();
//创建布隆过滤器的参数设置为页面大致数量即可
queueScheduler.setDuplicateRemover(new BloomFilterDuplicateRemover(100000));
//启动爬虫
Spider.create(pageProcessorDemo)
.addUrl(urls.toArray(new String[11]))
.addPipeline(myPipeline)
.addPipeline(new ConsolePipeline())
//配置管理url和对url去重的url管理器队列
.setScheduler(queueScheduler)
.thread(5)
.start();
return "ok";
}
Spider爬虫控制引擎的使用
- 使用静态方法create()指定一个页面处理器,然后创建一个Spider爬虫控制引擎
- 通过addUrl()方法,指定爬虫爬取的初始地址
- 有数据持久化需求可以通过setPipeline()添加数据持久化处理器,可以添加多个
- 通过thread()方法指定启动爬虫最多可以开启多少个线程
- 启动爬虫有三种方式
- run(),同步爬虫,在本线程进行爬虫
- start(),异步爬虫,开启一个新线程,在新的线程中进行爬虫
- runAsync,异步爬虫
public String start(){
String baseUrl = "https://www.shixiseng.com/interns?type=intern&keyword=java&area&months&days°ree&official&enterprise&salary=-0&publishTime&sortType&city=%E5%85%A8%E5%9B%BD&page=";
List<String> urls = new ArrayList<>();
for (int i = 1; i <= 11; i++) {
urls.add(baseUrl+i);
}
//启动爬虫
Spider.create(pageProcessorDemo)
.addUrl(urls.toArray(new String[11]))
.addPipeline(myPipeline)
.addPipeline(new ConsolePipeline())
.thread(5)
.start();
return "ok";
}
Site对象的使用
- 通过该对象可以设置爬取站点时,携带的信息,比如:浏览器类型,Cookie,等等
- 该对象需要配置页面处理器PageProcessor使用
@Bean
public Site shiXiSengSite(){
Site site = Site.me();
//设置浏览器类型
site.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36");
//设置cookie
Map<String, String> cookie = getCookie();
for (Map.Entry<String, String> entry : cookie.entrySet()) {
site.addCookie(entry.getKey(),entry.getValue());
}
return site;
}
定时爬虫
- 使用Spring提供的定时机制进行定时
- cron表达式参考
- 在线生成cron表达式
@Component
public class Timer {
/**
* 定时方式一
* 使用@Scheduled注解设置定时的规则
* 每间隔一秒启动一次
* fixedRate与fixedRateString作用等价,前者参数是数值,后者参数是数值的字符串
*/
@Scheduled(fixedRate = 1000)
//@Scheduled(fixedRateString = "1000")
public void timingTest1(){
System.out.println("定时器1");
System.out.println("LocalDateTime.now().toLocalTime() = " + LocalDateTime.now().toLocalTime());
}
/**
* 定时方式二
* 当前任务执行完,等待一秒后再执行
*/
@Scheduled(fixedDelay = 1000)
//@Scheduled(fixedDelayString = "1000")
public void timingTest2(){
System.out.println("定时器二");
System.out.println("LocalDateTime.now().toLocalTime() = " + LocalDateTime.now().toLocalTime());
}
/**
* 定时方式三
* 使用cron表达式进行定时,间隔两秒执行一次
* 一共有七个占位符,依次表示秒,分钟,小时,日,月,周,年
* 最后一个占位符年,可以省略
*/
@Scheduled(cron = "0/2 * * * * * ")
public void cornTest(){
System.out.println("使用cron表达式设置定时任务");
System.out.println("LocalDateTime.now().toLocalTime() = " + LocalDateTime.now().toLocalTime());
}
}