mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-24 17:41:03 +01:00
264 lines
7.3 KiB
Go
264 lines
7.3 KiB
Go
package config_spider
|
|
|
|
//import (
|
|
// "errors"
|
|
// "fmt"
|
|
// "github.com/crawlab-team/crawlab/core/constants"
|
|
// "github.com/crawlab-team/crawlab/core/entity"
|
|
// "github.com/crawlab-team/crawlab/core/models"
|
|
// "github.com/crawlab-team/crawlab/core/utils"
|
|
// "path/filepath"
|
|
//)
|
|
//
|
|
//type ScrapyGenerator struct {
|
|
// Spider model.Spider
|
|
// ConfigData entity.ConfigSpiderData
|
|
//}
|
|
//
|
|
//// 生成爬虫文件
|
|
//func (g ScrapyGenerator) Generate() error {
|
|
// // 生成 items.py
|
|
// if err := g.ProcessItems(); err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // 生成 spider.py
|
|
// if err := g.ProcessSpider(); err != nil {
|
|
// return err
|
|
// }
|
|
// return nil
|
|
//}
|
|
//
|
|
//// 生成 items.py
|
|
//func (g ScrapyGenerator) ProcessItems() error {
|
|
// // 待处理文件名
|
|
// src := g.Spider.Src
|
|
// filePath := filepath.Join(src, "config_spider", "items.py")
|
|
//
|
|
// // 获取所有字段
|
|
// fields := g.GetAllFields()
|
|
//
|
|
// // 字段名列表(包含默认字段名)
|
|
// fieldNames := []string{
|
|
// "_id",
|
|
// "task_id",
|
|
// "ts",
|
|
// }
|
|
//
|
|
// // 加入字段
|
|
// for _, field := range fields {
|
|
// fieldNames = append(fieldNames, field.Name)
|
|
// }
|
|
//
|
|
// // 将字段名转化为python代码
|
|
// str := ""
|
|
// for _, fieldName := range fieldNames {
|
|
// line := g.PadCode(fmt.Sprintf("%s = scrapy.Field()", fieldName), 1)
|
|
// str += line
|
|
// }
|
|
//
|
|
// // 将占位符替换为代码
|
|
// if err := utils.SetFileVariable(filePath, constants.AnchorItems, str); err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// return nil
|
|
//}
|
|
//
|
|
//// 生成 spider.py
|
|
//func (g ScrapyGenerator) ProcessSpider() error {
|
|
// // 待处理文件名
|
|
// src := g.Spider.Src
|
|
// filePath := filepath.Join(src, "config_spider", "spiders", "spider.py")
|
|
//
|
|
// // 替换 start_stage
|
|
// if err := utils.SetFileVariable(filePath, constants.AnchorStartStage, "parse_"+GetStartStageName(g.ConfigData)); err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // 替换 start_url
|
|
// if err := utils.SetFileVariable(filePath, constants.AnchorStartUrl, g.ConfigData.StartUrl); err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // 替换 parsers
|
|
// strParser := ""
|
|
// for _, stage := range g.ConfigData.Stages {
|
|
// stageName := stage.Name
|
|
// stageStr := g.GetParserString(stageName, stage)
|
|
// strParser += stageStr
|
|
// }
|
|
// if err := utils.SetFileVariable(filePath, constants.AnchorParsers, strParser); err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// return nil
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetParserString(stageName string, stage entity.Stage) string {
|
|
// // 构造函数定义行
|
|
// strDef := g.PadCode(fmt.Sprintf("def parse_%s(self, response):", stageName), 1)
|
|
//
|
|
// strParse := ""
|
|
// if stage.IsList {
|
|
// // 列表逻辑
|
|
// strParse = g.GetListParserString(stageName, stage)
|
|
// } else {
|
|
// // 非列表逻辑
|
|
// strParse = g.GetNonListParserString(stageName, stage)
|
|
// }
|
|
//
|
|
// // 构造
|
|
// str := fmt.Sprintf(`%s%s`, strDef, strParse)
|
|
//
|
|
// return str
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) PadCode(str string, num int) string {
|
|
// res := ""
|
|
// for i := 0; i < num; i++ {
|
|
// res += " "
|
|
// }
|
|
// res += str
|
|
// res += "\n"
|
|
// return res
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetNonListParserString(stageName string, stage entity.Stage) string {
|
|
// str := ""
|
|
//
|
|
// // 获取或构造item
|
|
// str += g.PadCode("item = Item() if response.meta.get('item') is None else response.meta.get('item')", 2)
|
|
//
|
|
// // 遍历字段列表
|
|
// for _, f := range stage.Fields {
|
|
// line := fmt.Sprintf(`item['%s'] = response.%s.extract_first()`, f.Name, g.GetExtractStringFromField(f))
|
|
// line = g.PadCode(line, 2)
|
|
// str += line
|
|
// }
|
|
//
|
|
// // next stage 字段
|
|
// if f, err := g.GetNextStageField(stage); err == nil {
|
|
// // 如果找到 next stage 字段,进行下一个回调
|
|
// str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url="get_real_url(response, item['%s'])", callback=self.parse_%s, meta={'item': item})`, f.Name, f.NextStage), 2)
|
|
// } else {
|
|
// // 如果没找到 next stage 字段,返回 item
|
|
// str += g.PadCode(fmt.Sprintf(`yield item`), 2)
|
|
// }
|
|
//
|
|
// // 加入末尾换行
|
|
// str += g.PadCode("", 0)
|
|
//
|
|
// return str
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetListParserString(stageName string, stage entity.Stage) string {
|
|
// str := ""
|
|
//
|
|
// // 获取前一个 stage 的 item
|
|
// str += g.PadCode(`prev_item = response.meta.get('item')`, 2)
|
|
//
|
|
// // for 循环遍历列表
|
|
// str += g.PadCode(fmt.Sprintf(`for elem in response.%s:`, g.GetListString(stage)), 2)
|
|
//
|
|
// // 构造item
|
|
// str += g.PadCode(`item = Item()`, 3)
|
|
//
|
|
// // 遍历字段列表
|
|
// for _, f := range stage.Fields {
|
|
// line := fmt.Sprintf(`item['%s'] = elem.%s.extract_first()`, f.Name, g.GetExtractStringFromField(f))
|
|
// line = g.PadCode(line, 3)
|
|
// str += line
|
|
// }
|
|
//
|
|
// // 把前一个 stage 的 item 值赋给当前 item
|
|
// str += g.PadCode(`if prev_item is not None:`, 3)
|
|
// str += g.PadCode(`for key, value in prev_item.items():`, 4)
|
|
// str += g.PadCode(`item[key] = value`, 5)
|
|
//
|
|
// // next stage 字段
|
|
// if f, err := g.GetNextStageField(stage); err == nil {
|
|
// // 如果 url 为空,则不进入下一个 stage
|
|
// str += g.PadCode(fmt.Sprintf(`if not item['%s']:`, f.Name), 3)
|
|
// str += g.PadCode(`continue`, 4)
|
|
//
|
|
// // 如果找到 next stage 字段,进行下一个回调
|
|
// str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url=get_real_url(response, item['%s']), callback=self.parse_%s, meta={'item': item})`, f.Name, f.NextStage), 3)
|
|
// } else {
|
|
// // 如果没找到 next stage 字段,返回 item
|
|
// str += g.PadCode(fmt.Sprintf(`yield item`), 3)
|
|
// }
|
|
//
|
|
// // 分页
|
|
// if stage.PageCss != "" || stage.PageXpath != "" {
|
|
// str += g.PadCode(fmt.Sprintf(`next_url = response.%s.extract_first()`, g.GetExtractStringFromStage(stage)), 2)
|
|
// str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url=get_real_url(response, next_url), callback=self.parse_%s, meta={'item': prev_item})`, stageName), 2)
|
|
// }
|
|
//
|
|
// // 加入末尾换行
|
|
// str += g.PadCode("", 0)
|
|
//
|
|
// return str
|
|
//}
|
|
//
|
|
//// 获取所有字段
|
|
//func (g ScrapyGenerator) GetAllFields() []entity.Field {
|
|
// return GetAllFields(g.ConfigData)
|
|
//}
|
|
//
|
|
//// 获取包含 next stage 的字段
|
|
//func (g ScrapyGenerator) GetNextStageField(stage entity.Stage) (entity.Field, error) {
|
|
// for _, field := range stage.Fields {
|
|
// if field.NextStage != "" {
|
|
// return field, nil
|
|
// }
|
|
// }
|
|
// return entity.Field{}, errors.New("cannot find next stage field")
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetExtractStringFromField(f entity.Field) string {
|
|
// if f.Css != "" {
|
|
// // 如果为CSS
|
|
// if f.Attr == "" {
|
|
// // 文本
|
|
// return fmt.Sprintf(`css('%s::text')`, f.Css)
|
|
// } else {
|
|
// // 属性
|
|
// return fmt.Sprintf(`css('%s::attr("%s")')`, f.Css, f.Attr)
|
|
// }
|
|
// } else {
|
|
// // 如果为XPath
|
|
// if f.Attr == "" {
|
|
// // 文本
|
|
// return fmt.Sprintf(`xpath('string(%s)')`, f.Xpath)
|
|
// } else {
|
|
// // 属性
|
|
// return fmt.Sprintf(`xpath('%s/@%s')`, f.Xpath, f.Attr)
|
|
// }
|
|
// }
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetExtractStringFromStage(stage entity.Stage) string {
|
|
// // 分页元素属性,默认为 href
|
|
// pageAttr := "href"
|
|
// if stage.PageAttr != "" {
|
|
// pageAttr = stage.PageAttr
|
|
// }
|
|
//
|
|
// if stage.PageCss != "" {
|
|
// // 如果为CSS
|
|
// return fmt.Sprintf(`css('%s::attr("%s")')`, stage.PageCss, pageAttr)
|
|
// } else {
|
|
// // 如果为XPath
|
|
// return fmt.Sprintf(`xpath('%s/@%s')`, stage.PageXpath, pageAttr)
|
|
// }
|
|
//}
|
|
//
|
|
//func (g ScrapyGenerator) GetListString(stage entity.Stage) string {
|
|
// if stage.ListCss != "" {
|
|
// return fmt.Sprintf(`css('%s')`, stage.ListCss)
|
|
// } else {
|
|
// return fmt.Sprintf(`xpath('%s')`, stage.ListXpath)
|
|
// }
|
|
//}
|