当前位置:   article > 正文

java爬虫---爬取某直聘招聘信息(超详细版)_招聘信息爬取

招聘信息爬取

如有侵权,请联系删除。(求BOSS直聘放过)

前言:

我们爬取BOSS直聘的网站的方式是比较固定的,基本上爬取网站的方式都差不多。
静态网页的爬取比较简单,如下:

我们只需要获取网页的源代码,按照一些解析器,就可以完成对页面元素的获取。
动态网页就比较麻烦了,如下:

就是一堆JS的链接。。。。。

不过既然我们正常浏览器可以访问得到我们想要的结果,那我们就一定有机会拿到我们想要的数据;
这次我采取的方案是,比较水、比较慢的一种方案;WebMagic+selenium爬取页面元素,POI实现Excel存储,最终结果没有入库,直接导出了;

前期准备:

  • 下载驱动: 首先我们需要下载谷歌的驱动,可以去下面网址下载ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)
  • 下载Excel 本次使用的是xlsx后缀的新版本Excel
  • Java的运行环境
  • 使用Maven搭建项目,导入依赖
    1. <!-- https://mvnrepository.com/artifact/us.codecraft/webmagic-core -->
    2. <dependency>
    3. <groupId>us.codecraft</groupId>
    4. <artifactId>webmagic-core</artifactId>
    5. <version>0.8.0</version>
    6. </dependency>
    7. <!-- https://mvnrepository.com/artifact/us.codecraft/webmagic-extension -->
    8. <dependency>
    9. <groupId>us.codecraft</groupId>
    10. <artifactId>webmagic-extension</artifactId>
    11. <version>0.8.0</version>
    12. </dependency>
    13. <!--selenium依赖-->
    14. <dependency>
    15. <groupId>org.seleniumhq.selenium</groupId>
    16. <artifactId>selenium-java</artifactId>
    17. <version>3.13.0</version>
    18. </dependency>
    19. <!--配置POI-->
    20. <dependency>
    21. <groupId>org.apache.poi</groupId>
    22. <artifactId>poi</artifactId>
    23. <version>3.14</version>
    24. </dependency>
    25. <dependency>
    26. <groupId>org.apache.poi</groupId>
    27. <artifactId>poi-ooxml</artifactId>
    28. <version>3.14</version>
    29. </dependency>
    30. <dependency>
    31. <groupId>org.projectlombok</groupId>
    32. <artifactId>lombok</artifactId>
    33. <version>1.18.24</version>
    34. </dependency>
  • 检索结果的pojo
    1. @Data
    2. public class WorkInf {
    3. //招聘链接
    4. private String url;
    5. //工作名
    6. private String workName;
    7. //薪水
    8. private String workSalary;
    9. //工作地址
    10. private String workAddress;
    11. //工作内容
    12. private String workContent;
    13. //要求工作年限
    14. private String workYear;
    15. //学历
    16. private String graduate;
    17. //招聘人什么时候活跃
    18. private String HRTime;
    19. //公司名
    20. private String companyName;
    21. }

代码:

代码对着WebMagic来一步步实现;想学Java爬虫的兄弟一定要先记住这幅图,可以找教程学学;

浏览器模拟(Download部分):

上面讲了,动态页面没法直接通过获取源代码来实现爬取,所以我们要实现一个伪造的浏览器;selenium就帮我们很好的实现了这个技术(当然还有别的更好的解决方案,我感觉这个比较简单就用了这个)

首先我们需要下载谷歌的驱动,可以去下面网址下载ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)

  1. public class ChromeDownloader implements Downloader {
  2. //声明驱动
  3. private RemoteWebDriver driver;
  4. public ChromeDownloader() {
  5. //第一个参数是使用哪种浏览器驱动
  6. //第二个参数是浏览器驱动的地址
  7. System.setProperty("webdriver.chrome.driver","谷歌驱动的下载地址,chromedriver.exe");
  8. //创建浏览器参数对象
  9. ChromeOptions chromeOptions = new ChromeOptions();
  10. // chromeOptions.addArguments("--headless");
  11. // 设置浏览器窗口打开大小
  12. chromeOptions.addArguments("--window-size=1280,700");
  13. //创建驱动
  14. this.driver = new ChromeDriver(chromeOptions);
  15. }
  16. @Override
  17. public Page download(Request request, Task task) {
  18. try {
  19. driver.get(request.getUrl());
  20. Thread.sleep(1500);
  21. //无论是搜索页还是详情页,都滚动到页面底部,所有该加载的资源都加载
  22. driver.executeScript("window.scrollTo(0, document.body.scrollHeight - 1000)");
  23. Thread.sleep(1500l);
  24. //获取页面对象
  25. Page page = createPage(request.getUrl(), driver.getPageSource());
  26. //关闭浏览器
  27. //driver.close();
  28. return page;
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. return null;
  33. }
  34. @Override
  35. public void setThread(int i) {
  36. }
  37. //构建page返回对象
  38. private Page createPage(String url, String content) {
  39. Page page = new Page();
  40. page.setRawText(content);
  41. page.setUrl(new PlainText(url));
  42. page.setRequest(new Request(url));
  43. page.setDownloadSuccess(true);
  44. /* System.out.println("==============page内容===============");
  45. System.out.println("1."+content);
  46. System.out.println("2."+new PlainText(url));
  47. System.out.println("3."+new Request(url));
  48. System.out.println("=====================================");*/
  49. return page;
  50. }
  51. }

 这里的代码直接抄就好了;

对页面进行解析(PageProcesser部分)

这里的逻辑分成两个部分,首先是BOSS的导航页,在这里我们可以拿到每一个工作的详情页的地址,然后把详情页地址添加到我们的Scheduler中,我们的爬虫程序有爬取的目标;

然后就是详情页,我们需要对其中的信息进行检索解析。

  1. public class BoosProcessor implements PageProcessor {
  2. public static AtomicInteger pageNum = new AtomicInteger(2);
  3. @Override
  4. public void process(Page page) {
  5. //去抓取职位列表
  6. List<Selectable> nodes = page.getHtml().css("li.job-card-wrapper").nodes();
  7. if(nodes != null && nodes.size() > 0 || page.getUrl().get().contains("geek/job")){
  8. //有值就是工作列表页
  9. //遍历所有的列表项,拿超链接
  10. for (Selectable node : nodes) {
  11. String s = node.css("a.job-card-left").links().get();
  12. page.addTargetRequest(s);
  13. }
  14. page.addTargetRequest("https://www.zhipin.com/web/geek/job?query=java实习&city=101280100&page="+pageNum.getAndIncrement());
  15. }else {
  16. //工作详情页 处理我们想要的信息,我这里都用了CSS选择器
  17. Selectable biggest = page.getHtml().css("div#wrap");
  18. WorkInf workInf = new WorkInf();
  19. Selectable primary = biggest.css("div.info-primary");
  20. String workName = primary.css("div.name h1").get();
  21. String salary = primary.css("div.name span").get();
  22. String year = primary.css("p span.text-experiece").get();
  23. String graduate = primary.css("p span.text-desc.text-degree").get();
  24. Selectable jobDetail = biggest.css("div.job-detail");
  25. String workContent = jobDetail.css("div.job-detail-section div.job-sec-text").get();
  26. String HrTime = jobDetail.css("h2.name span").get();
  27. Selectable jobSider = biggest.css("div.job-sider");
  28. String companyName = jobSider.css("div.sider-company a[ka=job-detail-company_custompage]").get();
  29. String workAddress = jobDetail.css("div.location-address").get();
  30. workInf.setWorkName(Jsoup.parse(workName).text());
  31. workInf.setWorkSalary(Jsoup.parse(salary).text());
  32. workInf.setWorkYear(Jsoup.parse(year).text());
  33. workInf.setGraduate(Jsoup.parse(graduate).text());
  34. workInf.setWorkContent(Jsoup.parse(workContent).text());
  35. workInf.setHRTime(Jsoup.parse(HrTime).text());
  36. workInf.setCompanyName(Jsoup.parse(companyName).text());
  37. workInf.setWorkAddress(Jsoup.parse(workAddress).text());
  38. workInf.setUrl(page.getUrl().get());
  39. page.putField("workInf",workInf);
  40. }
  41. }
  42. //可以对爬虫进行一些配置
  43. private Site site = Site.me()
  44. // 单位是秒
  45. .setCharset("UTF-8")//编码
  46. .setSleepTime(1)//抓取间隔时间,可以解决一些反爬限制
  47. .setTimeOut(1000 * 10)//超时时间
  48. .setRetrySleepTime(3000)//重试时间
  49. .setRetryTimes(3);//重试次数
  50. @Override
  51. public Site getSite() {
  52. return site;
  53. }
  54. }

结果存储(Pipeline部分)

我没有让数据入库,而是直接导出到了Excel文件中。

  1. public class BoosPipeline implements Pipeline {
  2. private final static String excel2003L =".xls"; //2003- 版本的excel
  3. private final static String excel2007U =".xlsx"; //2007+ 版本的excel
  4. public static Integer integer= new Integer(0);
  5. public static List<WorkInf> workInfList = new ArrayList<>();
  6. @Override
  7. public void process(ResultItems result, Task task) {
  8. //设计存储过程
  9. WorkInf workInf = result.get("workInf");
  10. if(workInf==null){
  11. return;
  12. }
  13. synchronized (BoosPipeline.class){
  14. workInfList.add(workInf);
  15. /*try {
  16. Thread.sleep(500);
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }*/
  20. //多线程的话在这里获取一下锁
  21. int howManyWorkStart = 10;
  22. if(workInfList.size() >= howManyWorkStart){
  23. //追加存到Excel中
  24. try {
  25. String path = "Z:\\climbResult\\BOOSWork_java.xlsx";
  26. FileInputStream fileInputStream = new FileInputStream(path);
  27. XSSFWorkbook workbook=new XSSFWorkbook(fileInputStream);//得到文档对象
  28. Sheet sheet = workbook.getSheetAt(0);
  29. int lastRowNum = sheet.getLastRowNum();
  30. for(int i = 1 ; i<=howManyWorkStart ;i++){
  31. WorkInf inf = workInfList.get(i-1);
  32. Row row = sheet.createRow(lastRowNum+i);
  33. for(int j = 0 ; j < 9 ; j++){
  34. Cell cell = row.createCell(j);
  35. switch (j){
  36. case 0 : cell.setCellValue(inf.getUrl()); break;
  37. case 1 : cell.setCellValue(inf.getWorkName()); break;
  38. case 2 : cell.setCellValue(inf.getWorkSalary()); break;
  39. case 3 : cell.setCellValue(inf.getWorkAddress()); break;
  40. case 4 : cell.setCellValue(inf.getWorkContent()); break;
  41. case 5 : cell.setCellValue(inf.getWorkYear()); break;
  42. case 6 : cell.setCellValue(inf.getGraduate()); break;
  43. case 7 : cell.setCellValue(inf.getHRTime()); break;
  44. case 8 : cell.setCellValue(inf.getCompanyName()); break;
  45. default: break;
  46. }
  47. }
  48. }
  49. FileOutputStream fileOutputStream = new FileOutputStream(path);
  50. fileOutputStream.flush();
  51. workbook.write(fileOutputStream);
  52. fileOutputStream.close();
  53. //清空List
  54. workInfList.clear();
  55. System.out.println("===============workInfSize=======================");
  56. System.out.println("当前workInfList的长度为:"+workInfList.size()+"完成一轮爬取");
  57. System.out.println("==================================================");
  58. integer++;
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. if(integer>500){
  64. System.exit(0);
  65. }
  66. }
  67. }
  68. /*根据文件的后缀名去确定workbook的类型*/
  69. public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception{
  70. Workbook wb = null;
  71. String fileType = fileName.substring(fileName.lastIndexOf("."));
  72. if(excel2003L.equals(fileType)){
  73. wb = new HSSFWorkbook(inStr); //2003-
  74. }else if(excel2007U.equals(fileType)){
  75. wb = new XSSFWorkbook(inStr); //2007+
  76. }else{
  77. throw new Exception("解析的文件格式有误!");
  78. }
  79. return wb;
  80. }
  81. }

保存结果如下图所示:

启动类(程序入口):

将我们上面写的类,放入到Spider中,Spider这个类负责管理整个爬虫程序;

  1. public class StartClimb {
  2. public static void main(String[] args) {
  3. ChromeDownloader downloader = new ChromeDownloader();
  4. BoosPipeline boosPipeline = new BoosPipeline();
  5. //声明搜索页的初始地址
  6. String url = "https://www.zhipin.com/web/geek/job?query=java实习&city=101280100";
  7. Spider.create(new BoosProcessor())
  8. .addUrl(url)
  9. //设置下载器
  10. .setDownloader(downloader)
  11. //设置输出
  12. .addPipeline(boosPipeline)
  13. .run();
  14. }
  15. }

开始运行,大功告成,因为要模拟浏览器访问,所以速度是比较慢的,一分钟可能也就爬取4到5条想要的结果,不过有螃蟹吃,是不是已经很香了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/517013
推荐阅读
相关标签
  

闽ICP备14008679号