lizongze 8 ヶ月 前
コミット
aa9b58e7cd

+ 86 - 0
湖南轨道集团招采平台/hngdjtzcpt_pm.js

@@ -0,0 +1,86 @@
+const jsdom = require("jsdom");
+const {JSDOM} = jsdom;
+const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`,
+    {
+        url: "https://example.org/",
+        referrer: "https://example.com/",
+        contentType: "text/html",
+    });
+window = dom.window;
+
+
+CryptoJs = require('crypto-js')
+
+function get_flag() {
+    var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 16
+        , n = Math.random().toString(36).substring(2);
+    if (n.length >= t)
+        return n.substring(0, t);
+    return n += get_flag(t - n.length),
+        n
+}
+
+function get_f() {
+    var r = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    var ee = window.crypto.getRandomValues(new Uint8Array(18))
+    var t, n;
+    for (t = [],
+             n = 0; n < ee.length; n++)
+        t.push(r[ee[n] % 62]);
+    return t.join("")
+}
+
+function traceId() {
+    this.seedUniquifier = 8682522807148012
+    this.multiplier = 25214903917
+    this.addend = 11
+    this.mask = 0xffffffffffff
+    this.seed = 0
+    this.step = 1
+    this.fseedUniquifier = function () {
+        var e = 0x285d320ad33fdc0 * this.seedUniquifier;
+        return this.seedUniquifier = e,
+            e
+    }
+
+    this.initialScramble = function (e) {
+        return (e ^ this.multiplier) & this.mask
+    }
+
+    this.nextLong = function () {
+        var e = (new Date).getTime();
+        return this.seed = this.initialScramble(this.fseedUniquifier() ^ e + Math.round(100 * Math.random())),
+        this.next(32, !1) + this.next(32, !0)
+    }
+
+    this.next = function (e, t) {
+        var n = this.seed * this.multiplier + this.addend & this.mask;
+        this.seed = n,
+            n = Math.abs(n) + Math.round(100 * Math.random()) + this.step,
+            this.step++,
+        this.step >= 999999 && (this.step = 1);
+        for (var r = n.toString(2); r.length < 32;)
+            r = "0" + r;
+        return (n = parseInt(r, 2)).toString(16)
+    }
+
+    return this.nextLong()
+}
+
+function signature(ctime, token, resdate) {
+    var dft = serverDiffTime(resdate)
+    var data = ctime + token + '-' + dft + '[{"key":"","methodName":"loadData","args":[],"postData":[]}]'
+    return CryptoJs.SHA256(data).toString(CryptoJs.enc.Hex) + "-" + dft
+}
+
+function serverDiffTime(t) {
+    var n = new Date(t).getTime()
+        , i = Date.now();
+    r_o = i - (Number.isNaN(n) ? 0 : n)
+    return r_o.toString().substring(0, 3)
+}
+
+
+
+
+

+ 90 - 0
湖南轨道集团招采平台/中标公告-列表页.py

@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 湖南轨道集团招采平台
+---------
+@author: lzz
+"""
+import feapder
+from items.spider_item import BidingListItem
+from collections import namedtuple
+
+
+class ZtbpcFeapder(feapder.BiddingListSpider):
+
+    def start_callback(self):
+
+        self.site = "湖南轨道集团招采平台"
+
+        Menu = namedtuple('Menu', ['channel', 'code', 'crawl_page'])
+
+        self.menus = [
+            Menu('中标公告', 'a_hngdjtzcpt_zhbgg', 1),
+        ]
+
+        self.headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Referer": "https://hnrt.kdcloud.com/kingdee/pur/srmportal/srmportal.html?",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "accountId": "",
+        }
+
+
+    def start_requests(self):
+        for menu in self.menus:
+            start_url = "https://hnrt.kdcloud.com/kapi/app/srm/srmwebapi"
+            yield feapder.Request(url=start_url, item=menu._asdict(), page=1, proxies=False)
+
+    def download_midware(self, request):
+        page = request.page
+        params = {
+            "page": f"{page}",
+            "size": "20",
+            "type": "5,A,B,bidproject",
+            "apiname": "getPortalNoticeData",
+            "methodname": "getPortalNoticeData",
+            "accountId": ""
+        }
+        request.params = params
+        request.headers = self.headers
+
+    def parse(self, request, response):
+
+        menu = request.item
+        info_list = response.json.get('data').get('noticedata')
+        for info in info_list:
+            title = info.get('noticename').strip()
+            href = info.get('url')
+            publish_time = info.get('publishtime')
+
+            area = "湖南"
+            city = ""
+
+            list_item = BidingListItem()  # 存储数据的管道
+            list_item.href = href  # 标书链接
+            list_item.channel = menu.get("channel")  # 最上方定义的抓取栏目 (编辑器定的)
+            list_item.spidercode = menu.get("code")  # 最上方定义的爬虫code(编辑器定的)
+            list_item.title = title  # 标题
+            list_item.publishtime = publish_time  # 标书发布时间
+            list_item.site = self.site
+            list_item.area = area or "全国"  # 省份 默认:全国
+            list_item.city = city  # 城市 默认 为空
+
+            list_item.unique_key = ('href',)
+            list_item.parse = "self.detail_get"  # 详情页回调方法
+
+            list_item.parse_url = "https://hnrt.kdcloud.com/form/batchInvokeAction.do?appId=quo&f=quo_notice&ac=loadData"
+
+            yield list_item
+
+        request = self.infinite_pages(request, response)
+        yield request
+
+
+if __name__ == "__main__":
+    ZtbpcFeapder(redis_key="lzz:hngdjtzcpt_zhbgg").start()

+ 91 - 0
湖南轨道集团招采平台/招标公告-列表页.py

@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 湖南轨道集团招采平台
+---------
+@author: lzz
+"""
+import feapder
+from items.spider_item import BidingListItem
+from collections import namedtuple
+
+
+class ZtbpcFeapder(feapder.BiddingListSpider):
+
+    def start_callback(self):
+
+        self.site = "湖南轨道集团招采平台"
+
+        Menu = namedtuple('Menu', ['channel', 'code', 'crawl_page'])
+
+        self.menus = [
+            Menu('招标公告', 'a_hngdjtzcpt_zbgg', 1),
+        ]
+
+        self.headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Referer": "https://hnrt.kdcloud.com/kingdee/pur/srmportal/srmportal.html?",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "accountId": "",
+        }
+
+
+    def start_requests(self):
+        for menu in self.menus:
+            start_url = "https://hnrt.kdcloud.com/kapi/app/srm/srmwebapi"
+            yield feapder.Request(url=start_url, item=menu._asdict(), page=1, proxies=False)
+
+    def download_midware(self, request):
+        page = request.page
+        params = {
+            "page": f"{page}",
+            "size": "20",
+            "type": "1,2,3,4,C,bidproject",
+            "componentid": "1484094329416073216",
+            "apiname": "getPortalNoticeData",
+            "methodname": "getPortalNoticeData",
+            "accountId": ""
+        }
+        request.params = params
+        request.headers = self.headers
+
+    def parse(self, request, response):
+
+        menu = request.item
+        info_list = response.json.get('data').get('noticedata')
+        for info in info_list:
+            title = info.get('noticename').strip()
+            href = info.get('url')
+            publish_time = info.get('publishtime')
+
+            area = "湖南"
+            city = ""
+
+            list_item = BidingListItem()  # 存储数据的管道
+            list_item.href = href  # 标书链接
+            list_item.channel = menu.get("channel")  # 最上方定义的抓取栏目 (编辑器定的)
+            list_item.spidercode = menu.get("code")  # 最上方定义的爬虫code(编辑器定的)
+            list_item.title = title  # 标题
+            list_item.publishtime = publish_time  # 标书发布时间
+            list_item.site = self.site
+            list_item.area = area or "全国"  # 省份 默认:全国
+            list_item.city = city  # 城市 默认 为空
+
+            list_item.unique_key = ('href',)
+            list_item.parse = "self.detail_get"  # 详情页回调方法
+
+            list_item.parse_url = "https://hnrt.kdcloud.com/form/batchInvokeAction.do?appId=quo&f=quo_notice&ac=loadData"
+
+            yield list_item
+
+        request = self.infinite_pages(request, response)
+        yield request
+
+
+if __name__ == "__main__":
+    ZtbpcFeapder(redis_key="lzz:hngdjtzcpt_zhbgg").start()

+ 187 - 0
湖南轨道集团招采平台/招采平台-详情页.py

@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 湖南轨道集团招采平台
+---------
+@author: lzz
+"""
+import re
+import feapder
+from items.spider_item import DataBakItem
+from untils.tools import extract_file_type
+from untils.attachment import AttachmentDownloader
+import requests
+import random
+import execjs
+import time
+import html
+import warnings
+
+warnings.filterwarnings('ignore')
+
+
+def get_pageId(hid, proxies=False):
+    try:
+        session = requests.session()
+        session.proxies = proxies
+        session.verify = False
+
+        with open('./hngdjtzcpt_pm.js', 'r') as fr:
+            ex_js = fr.read()
+
+        ctx = execjs.compile(ex_js)
+
+        flag = ctx.call('get_flag')
+        f = ctx.call('get_f')
+
+        headers = {
+            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Upgrade-Insecure-Requests": "1",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+        }
+        url = "https://hnrt.kdcloud.com/index.html"
+        params = {
+            "formId": "quo_notice",
+            "noticeId": hid,
+            "userId": "guest"
+        }
+        res = session.get(url, headers=headers, params=params, timeout=20)
+        traceId = res.headers.get('traceId')
+
+        headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Content-Type": "text/json;charset=utf-8;",
+            "Pragma": "no-cache",
+            "Referer": f"https://hnrt.kdcloud.com/index.html?formId=quo_notice&noticeId={hid}&userId=guest",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "ajax": "true",
+            "client-start-time": f"{int(time.time() * 1000)}",
+            "cqappid": "bos",
+            "traceId": traceId,
+            "userId": "1549127685240838144_-1"
+        }
+
+        url = f"https://hnrt.kdcloud.com/form/getConfig.do?params=%7B%22formId%22%3A%22quo_notice%22%2C%22noticeId%22%3A%22{hid}%22%2C%22userId%22%3A%22guest%22%2C%22flag%22%3A%22{flag}%22%2C%22f%22%3A%22{f}%22%7D&random={random.random()}"
+
+        resp = session.get(url, headers=headers, timeout=20)
+
+        cookies = session.cookies.get_dict()
+        token = resp.headers.get('kd-csrf-token')
+        pageId = resp.json().get('pageId')
+        resdate = resp.headers.get('Date')
+        new_traceId = resp.headers.get('traceId')
+
+        ctime = str(int(time.time() * 1000))
+        headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Content-Type": "application/x-www-form-urlencoded;charset=utf-8;",
+            "Origin": "https://hnrt.kdcloud.com",
+            "Pragma": "no-cache",
+            "Referer": f"https://hnrt.kdcloud.com/index.html?formId=quo_notice&noticeId={hid}&userId=guest",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "ajax": "true",
+            "client-start-time": ctime,
+            "cqappid": "quo",
+            "kd-csrf-token": token,
+            "signature": f"{ctx.call('signature', ctime, token, resdate)}__length__60",
+            "traceId": new_traceId,
+            "userId": "1549127685240838144_-1"
+        }
+
+        return token, pageId, headers, cookies
+    except:
+        return ""
+
+fheaders = {
+    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+    "Cache-Control": "no-cache",
+    "Connection": "keep-alive",
+    "Content-Type": "application/x-www-form-urlencoded",
+    "Origin": "https://hnrt.kdcloud.com/",
+    "Pragma": "no-cache",
+    "Upgrade-Insecure-Requests": "1",
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+}
+
+class Details(feapder.BiddingDetailSpider):
+    token = ""
+    pageId = ""
+    cookies = None
+
+    def start_requests(self):
+        data_lsit = self.get_tasks_by_rabbitmq(limit=10)
+        for item in data_lsit:
+            request_params = item.get("request_params")
+            timeout = request_params.get('timeout', 20)
+            request_params.pop('timeout', None)
+            yield feapder.Request(url=item.get("parse_url"), item=item,
+                                  deal_detail=item.get("deal_detail"), callback=eval(item.get("parse")),
+                                  **request_params, timeout=timeout, proxies=False)
+
+    def download_midware(self, request):
+
+        href = request.item.get('href')
+        hid = "".join(re.findall("noticeId=(.*?)&", href))
+        self.token, self.pageId, headers, self.cookies = get_pageId(hid)
+
+        data = {
+            "pageId": self.pageId,
+            "appId": "quo",
+            "params": "[{\"key\":\"\",\"methodName\":\"loadData\",\"args\":[],\"postData\":[]}]"
+        }
+        request.data = data
+        request.headers = headers
+        request.cookies = self.cookies
+
+    def detail_get(self, request, response):
+        items = request.item
+        list_item = DataBakItem(**items)
+
+        detail_html = ""
+        file_list = []
+        for tmp in response.json[0].get('p'):
+            if tmp.get('k') == "richtexteditor":
+                detail_html = html.unescape(tmp.get('v'))
+            if tmp.get('k') == "attachmentpanel":
+                file_list = tmp.get('data')
+
+        list_item.contenthtml = detail_html
+
+        attachments = {}
+        if file_list:
+            for info in file_list:
+                file_name = info.get('name','').strip()
+                file_url = "https://hnrt.kdcloud.com/" + info.get('downloadFilePath','') + f"&kd_cs_ticket={self.token}"
+                file_type = extract_file_type(file_name, file_url)
+                if file_type:
+                    data = {
+                        "fileName": file_name,
+                        "appId": "quo",
+                        "fId": "quo_notice",
+                        "pageId": self.pageId
+                    }
+                    attachment = AttachmentDownloader().fetch_attachment(method="POST",data=data,
+                        file_name=file_name, file_type=file_type, download_url=file_url,
+                        cookies=self.cookies, headers=fheaders)
+                    attachments[str(len(attachments) + 1)] = attachment
+
+        if attachments:
+            list_item.projectinfo = {"attachments": attachments}
+
+        yield list_item
+
+
+if __name__ == "__main__":
+    Details(redis_key="lzz:hngdjtzcpt_zhbgg").start()

+ 86 - 0
辽宁省环保集团有限责任公司/lnshbjtyxzrgs_pm.js

@@ -0,0 +1,86 @@
+const jsdom = require("jsdom");
+const {JSDOM} = jsdom;
+const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`,
+    {
+        url: "https://example.org/",
+        referrer: "https://example.com/",
+        contentType: "text/html",
+    });
+window = dom.window;
+
+
+CryptoJs = require('crypto-js')
+
+function get_flag() {
+    var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 16
+        , n = Math.random().toString(36).substring(2);
+    if (n.length >= t)
+        return n.substring(0, t);
+    return n += get_flag(t - n.length),
+        n
+}
+
+function get_f() {
+    var r = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    var ee = window.crypto.getRandomValues(new Uint8Array(18))
+    var t, n;
+    for (t = [],
+             n = 0; n < ee.length; n++)
+        t.push(r[ee[n] % 62]);
+    return t.join("")
+}
+
+function traceId() {
+    this.seedUniquifier = 8682522807148012
+    this.multiplier = 25214903917
+    this.addend = 11
+    this.mask = 0xffffffffffff
+    this.seed = 0
+    this.step = 1
+    this.fseedUniquifier = function () {
+        var e = 0x285d320ad33fdc0 * this.seedUniquifier;
+        return this.seedUniquifier = e,
+            e
+    }
+
+    this.initialScramble = function (e) {
+        return (e ^ this.multiplier) & this.mask
+    }
+
+    this.nextLong = function () {
+        var e = (new Date).getTime();
+        return this.seed = this.initialScramble(this.fseedUniquifier() ^ e + Math.round(100 * Math.random())),
+        this.next(32, !1) + this.next(32, !0)
+    }
+
+    this.next = function (e, t) {
+        var n = this.seed * this.multiplier + this.addend & this.mask;
+        this.seed = n,
+            n = Math.abs(n) + Math.round(100 * Math.random()) + this.step,
+            this.step++,
+        this.step >= 999999 && (this.step = 1);
+        for (var r = n.toString(2); r.length < 32;)
+            r = "0" + r;
+        return (n = parseInt(r, 2)).toString(16)
+    }
+
+    return this.nextLong()
+}
+
+function signature(ctime, token, resdate) {
+    var dft = serverDiffTime(resdate)
+    var data = ctime + token + '-' + dft + '[{"key":"","methodName":"loadData","args":[],"postData":[]}]'
+    return CryptoJs.SHA256(data).toString(CryptoJs.enc.Hex) + "-" + dft
+}
+
+function serverDiffTime(t) {
+    var n = new Date(t).getTime()
+        , i = Date.now();
+    r_o = i - (Number.isNaN(n) ? 0 : n)
+    return r_o.toString().substring(0, 3)
+}
+
+
+
+
+

+ 90 - 0
辽宁省环保集团有限责任公司/中标公告-列表页.py

@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 辽宁省环保集团有限责任公司
+---------
+@author: lzz
+"""
+import feapder
+from items.spider_item import BidingListItem
+from collections import namedtuple
+
+
+class ZtbpcFeapder(feapder.BiddingListSpider):
+
+    def start_callback(self):
+
+        self.site = "辽宁省环保集团有限责任公司"
+
+        Menu = namedtuple('Menu', ['channel', 'code', 'crawl_page'])
+
+        self.menus = [
+            Menu('招采平台-中标公告', 'a_lnshbjtyxzrgs_zcpt_zhbgg', 1),
+        ]
+
+        self.headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Referer": "https://lnepg.kdcloud.com/kingdee/pur/srmportal/srmportal.html",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "accountId;": "",
+        }
+
+
+    def start_requests(self):
+        for menu in self.menus:
+            start_url = "https://lnepg.kdcloud.com/kapi/app/srm/srmwebapi"
+            yield feapder.Request(url=start_url, item=menu._asdict(), page=1, proxies=False)
+
+    def download_midware(self, request):
+        page = request.page
+        params = {
+            "page": f"{page}",
+            "size": "20",
+            "type": "5,A,B",
+            "apiname": "getPortalNoticeData",
+            "methodname": "getPortalNoticeData",
+            "accountId": ""
+        }
+        request.params = params
+        request.headers = self.headers
+
+    def parse(self, request, response):
+
+        menu = request.item
+        info_list = response.json.get('data').get('noticedata')
+        for info in info_list:
+            title = info.get('noticename').strip()
+            href = info.get('url')
+            publish_time = info.get('publishtime')
+
+            area = "辽宁"
+            city = ""
+
+            list_item = BidingListItem()  # 存储数据的管道
+            list_item.href = href  # 标书链接
+            list_item.channel = menu.get("channel")  # 最上方定义的抓取栏目 (编辑器定的)
+            list_item.spidercode = menu.get("code")  # 最上方定义的爬虫code(编辑器定的)
+            list_item.title = title  # 标题
+            list_item.publishtime = publish_time  # 标书发布时间
+            list_item.site = self.site
+            list_item.area = area or "全国"  # 省份 默认:全国
+            list_item.city = city  # 城市 默认 为空
+
+            list_item.unique_key = ('href',)
+            list_item.parse = "self.detail_get"  # 详情页回调方法
+
+            list_item.parse_url = "https://lnepg.kdcloud.com/form/batchInvokeAction.do?appId=quo&f=quo_notice&ac=loadData"
+
+            yield list_item
+
+        request = self.infinite_pages(request, response)
+        yield request
+
+
+if __name__ == "__main__":
+    ZtbpcFeapder(redis_key="lzz:lnshbjtyxzrgs_zcpt_zbgg").start()

+ 91 - 0
辽宁省环保集团有限责任公司/招标公告-列表页.py

@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 辽宁省环保集团有限责任公司
+---------
+@author: lzz
+"""
+import feapder
+from items.spider_item import BidingListItem
+from collections import namedtuple
+
+
+class ZtbpcFeapder(feapder.BiddingListSpider):
+
+    def start_callback(self):
+
+        self.site = "辽宁省环保集团有限责任公司"
+
+        Menu = namedtuple('Menu', ['channel', 'code', 'crawl_page'])
+
+        self.menus = [
+            Menu('招采平台-招标公告', 'a_lnshbjtyxzrgs_zcpt_zbgg', 1),
+        ]
+
+        self.headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Referer": "https://lnepg.kdcloud.com/kingdee/pur/srmportal/srmportal.html",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "accountId;": "",
+        }
+
+
+    def start_requests(self):
+        for menu in self.menus:
+            start_url = "https://lnepg.kdcloud.com/kapi/app/srm/srmwebapi"
+            yield feapder.Request(url=start_url, item=menu._asdict(), page=1, proxies=False)
+
+    def download_midware(self, request):
+        page = request.page
+        params = {
+            "page": f"{page}",
+            "size": "20",
+            "type": "1,2,3,4,C",
+            "componentid": "1484094329416073216",
+            "apiname": "getPortalNoticeData",
+            "methodname": "getPortalNoticeData",
+            "accountId": ""
+        }
+        request.params = params
+        request.headers = self.headers
+
+    def parse(self, request, response):
+
+        menu = request.item
+        info_list = response.json.get('data').get('noticedata')
+        for info in info_list:
+            title = info.get('noticename').strip()
+            href = info.get('url')
+            publish_time = info.get('publishtime')
+
+            area = "辽宁"
+            city = ""
+
+            list_item = BidingListItem()  # 存储数据的管道
+            list_item.href = href  # 标书链接
+            list_item.channel = menu.get("channel")  # 最上方定义的抓取栏目 (编辑器定的)
+            list_item.spidercode = menu.get("code")  # 最上方定义的爬虫code(编辑器定的)
+            list_item.title = title  # 标题
+            list_item.publishtime = publish_time  # 标书发布时间
+            list_item.site = self.site
+            list_item.area = area or "全国"  # 省份 默认:全国
+            list_item.city = city  # 城市 默认 为空
+
+            list_item.unique_key = ('href',)
+            list_item.parse = "self.detail_get"  # 详情页回调方法
+
+            list_item.parse_url = "https://lnepg.kdcloud.com/form/batchInvokeAction.do?appId=quo&f=quo_notice&ac=loadData"
+
+            yield list_item
+
+        request = self.infinite_pages(request, response)
+        yield request
+
+
+if __name__ == "__main__":
+    ZtbpcFeapder(redis_key="lzz:lnshbjtyxzrgs_zcpt_zbgg").start()

+ 187 - 0
辽宁省环保集团有限责任公司/招采平台-详情页.py

@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 2024-12-06
+---------
+@summary: 辽宁省环保集团有限责任公司
+---------
+@author: lzz
+"""
+import re
+import feapder
+from items.spider_item import DataBakItem
+from untils.tools import extract_file_type
+from untils.attachment import AttachmentDownloader
+import requests
+import random
+import execjs
+import time
+import html
+import warnings
+
+warnings.filterwarnings('ignore')
+
+
+def get_pageId(hid, proxies=False):
+    try:
+        session = requests.session()
+        session.proxies = proxies
+        session.verify = False
+
+        with open('./lnshbjtyxzrgs_pm.js', 'r') as fr:
+            ex_js = fr.read()
+
+        ctx = execjs.compile(ex_js)
+
+        flag = ctx.call('get_flag')
+        f = ctx.call('get_f')
+
+        headers = {
+            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Pragma": "no-cache",
+            "Upgrade-Insecure-Requests": "1",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+        }
+        url = "https://lnepg.kdcloud.com/index.html"
+        params = {
+            "formId": "quo_notice",
+            "noticeId": hid,
+            "userId": "guest"
+        }
+        res = session.get(url, headers=headers, params=params, timeout=20)
+        traceId = res.headers.get('traceId')
+
+        headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Content-Type": "text/json;charset=utf-8;",
+            "Pragma": "no-cache",
+            "Referer": f"https://lnepg.kdcloud.com/index.html?formId=quo_notice&noticeId={hid}&userId=guest",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "ajax": "true",
+            "client-start-time": f"{int(time.time() * 1000)}",
+            "cqappid": "bos",
+            "traceId": traceId,
+            "userId": "1599869187784821760_-1"
+        }
+
+        url = f"https://lnepg.kdcloud.com/form/getConfig.do?params=%7B%22formId%22%3A%22quo_notice%22%2C%22noticeId%22%3A%22{hid}%22%2C%22userId%22%3A%22guest%22%2C%22flag%22%3A%22{flag}%22%2C%22f%22%3A%22{f}%22%7D&random={random.random()}"
+
+        resp = session.get(url, headers=headers, timeout=20)
+
+        cookies = session.cookies.get_dict()
+        token = resp.headers.get('kd-csrf-token')
+        pageId = resp.json().get('pageId')
+        resdate = resp.headers.get('Date')
+        new_traceId = resp.headers.get('traceId')
+
+        ctime = str(int(time.time() * 1000))
+        headers = {
+            "Accept": "*/*",
+            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+            "Cache-Control": "no-cache",
+            "Connection": "keep-alive",
+            "Content-Type": "application/x-www-form-urlencoded;charset=utf-8;",
+            "Origin": "https://lnepg.kdcloud.com",
+            "Pragma": "no-cache",
+            "Referer": f"https://lnepg.kdcloud.com/index.html?formId=quo_notice&noticeId={hid}&userId=guest",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+            "ajax": "true",
+            "client-start-time": ctime,
+            "cqappid": "quo",
+            "kd-csrf-token": token,
+            "signature": f"{ctx.call('signature', ctime, token, resdate)}__length__60",
+            "traceId": new_traceId,
+            "userId": "1599869187784821760_-1"
+        }
+
+        return token, pageId, headers, cookies
+    except:
+        return ""
+
+fheaders = {
+    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
+    "Cache-Control": "no-cache",
+    "Connection": "keep-alive",
+    "Content-Type": "application/x-www-form-urlencoded",
+    "Origin": "https://lnepg.kdcloud.com",
+    "Pragma": "no-cache",
+    "Upgrade-Insecure-Requests": "1",
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
+}
+
+class Details(feapder.BiddingDetailSpider):
+    token = ""
+    pageId = ""
+    cookies = None
+
+    def start_requests(self):
+        data_lsit = self.get_tasks_by_rabbitmq(limit=10)
+        for item in data_lsit:
+            request_params = item.get("request_params")
+            timeout = request_params.get('timeout', 20)
+            request_params.pop('timeout', None)
+            yield feapder.Request(url=item.get("parse_url"), item=item,
+                                  deal_detail=item.get("deal_detail"), callback=eval(item.get("parse")),
+                                  **request_params, timeout=timeout, proxies=False)
+
+    def download_midware(self, request):
+
+        href = request.item.get('href')
+        hid = "".join(re.findall("noticeId=(.*?)&", href))
+        self.token, self.pageId, headers, self.cookies = get_pageId(hid)
+
+        data = {
+            "pageId": self.pageId,
+            "appId": "quo",
+            "params": "[{\"key\":\"\",\"methodName\":\"loadData\",\"args\":[],\"postData\":[]}]"
+        }
+        request.data = data
+        request.headers = headers
+        request.cookies = self.cookies
+
+    def detail_get(self, request, response):
+        items = request.item
+        list_item = DataBakItem(**items)
+
+        detail_html = ""
+        file_list = []
+        for tmp in response.json[0].get('p'):
+            if tmp.get('k') == "richtexteditor":
+                detail_html = html.unescape(tmp.get('v'))
+            if tmp.get('k') == "attachmentpanel":
+                file_list = tmp.get('data')
+
+        list_item.contenthtml = detail_html
+
+        attachments = {}
+        if file_list:
+            for info in file_list:
+                file_name = info.get('name','').strip()
+                file_url = "https://lnepg.kdcloud.com/" + info.get('downloadFilePath','') + f"&kd_cs_ticket={self.token}"
+                file_type = extract_file_type(file_name, file_url)
+                if file_type:
+                    data = {
+                        "fileName": file_name,
+                        "appId": "quo",
+                        "fId": "quo_notice",
+                        "pageId": self.pageId
+                    }
+                    attachment = AttachmentDownloader().fetch_attachment(method="POST",data=data,
+                        file_name=file_name, file_type=file_type, download_url=file_url,
+                        cookies=self.cookies, headers=fheaders)
+                    attachments[str(len(attachments) + 1)] = attachment
+
+        if attachments:
+            list_item.projectinfo = {"attachments": attachments}
+
+        yield list_item
+
+
+if __name__ == "__main__":
+    Details(redis_key="lzz:lnshbjtyxzrgs_zcpt_zbgg").start()