写在开头

最近从新闻获悉,拉勾网主动申请破产,已进入破产重整程序。猛然回想起,我曾经在拉勾教育App买过几节课程,先不论课程质量如何,得赶在拉勾教育App彻底歇菜前将购买课程本地化。

思路

拉勾教育提供了网页版和移动端App,经过网页分析,直接使用爬虫程序抓起网页端内容做本地化存储即可。

步骤

  1. 登录拉勾教育网页版,获取登录凭证(Cookie和Authorization)

  2. 获取已购课程列表

  3. 获取课程目录

  4. 获取每节课程详情

    根据课程名、课程目录及每节课的名称存储课程详情数据,HTML格式

  5. 将每节课HTML转为PDF文件

    // htmlURLToPDF 将指定 URL(file:// 或 http://)渲染为 PDF 字节数组
    func htmlURLToPDF(url string) ([]byte, error) {
    	ctx, cancel := chromedp.NewContext(context.Background())
    	defer cancel()
    	ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
    	defer cancel()
    
    	var pdfBytes []byte
    	err := chromedp.Run(ctx,
    		chromedp.Navigate(url),
    		chromedp.Sleep(2*time.Second),
    		chromedp.ActionFunc(func(ctx context.Context) error {
    			var err error
    			pdfBytes, _, err = page.PrintToPDF().
    				WithPaperWidth(8.27).  // A4
    				WithPaperHeight(11.7). // A4
    				WithMarginTop(0.4).
    				WithMarginBottom(0.4).
    				WithMarginLeft(0.4).
    				WithMarginRight(0.4).
    				WithDisplayHeaderFooter(false). // 禁止页眉页脚,让分隔页干净
    				WithPreferCSSPageSize(true).
    				Do(ctx)
    			return err
    		}),
    	)
    	if err != nil {
    		return nil, fmt.Errorf("渲染 PDF 失败 %s: %v", url, err)
    	}
    	return pdfBytes, nil
    }
    
  6. 合并PDF并添加书签(关键代码)

    // 合并到临时文件
    tmpFile := output + ".tmp.pdf"
    log.Printf("正在合并 %d 个 PDF 单元...", len(items))
    if err := mergePDFReaders(readers, tmpFile); err != nil {
        return fmt.Errorf("合并失败: %v", err)
    }
    
    // 添加书签到最终 PDF
    log.Printf("正在添加书签(%d 个章节,共 %d 个条目)...", len(rootBookmarks), len(items))
    if err := api.AddBookmarks(inputFile, outputFile, rootBookmarks, true, nil); err != nil {
        return fmt.Errorf("添加书签失败: %v", err)
    }
    

成果展示

  1. HTML

  2. PDF