|
@@ -6,13 +6,14 @@ Created on 2025-04-18
|
|
|
---------
|
|
|
@author: lzz
|
|
|
"""
|
|
|
+import json
|
|
|
+import re
|
|
|
+
|
|
|
import feapder
|
|
|
from items.spider_item import DataBakItem
|
|
|
from untils.tools import get_proxy
|
|
|
-from create_ck import cr_ck,ff
|
|
|
-import json
|
|
|
-import re
|
|
|
|
|
|
+from create_ck import cr_ck, ff
|
|
|
|
|
|
headers = {
|
|
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
|
@@ -27,13 +28,13 @@ headers = {
|
|
|
"X-Requested-With": "XMLHttpRequest",
|
|
|
}
|
|
|
|
|
|
-class Details(feapder.BiddingDetailSpider):
|
|
|
+
|
|
|
+class Spider(feapder.BiddingDetailSpider):
|
|
|
|
|
|
cookies = {}
|
|
|
- ct = 0
|
|
|
proxy = get_proxy()
|
|
|
def start_requests(self):
|
|
|
- data_list = self.get_tasks_by_mongodb(limit=200)
|
|
|
+ data_list = self.get_tasks_by_rabbitmq(limit=200)
|
|
|
for item in data_list:
|
|
|
request_params = item.get("request_params")
|
|
|
if item.get('channel') == "采购公告":
|
|
@@ -51,12 +52,12 @@ class Details(feapder.BiddingDetailSpider):
|
|
|
dhref = request.item.get('href')
|
|
|
|
|
|
rfqMethod = "".join(re.findall('/rfqMethod=(.*?)/',dhref))
|
|
|
- id = "".join(re.findall('/id=(.*?)/',dhref))
|
|
|
+ id_ = "".join(re.findall('/id=(.*?)/', dhref))
|
|
|
data = {
|
|
|
"page": 1,
|
|
|
"rows": 100,
|
|
|
"rfqMethod": rfqMethod,
|
|
|
- "id": id,
|
|
|
+ "id": id_,
|
|
|
}
|
|
|
data = json.dumps(data, separators=(',', ':'))
|
|
|
|
|
@@ -65,198 +66,197 @@ class Details(feapder.BiddingDetailSpider):
|
|
|
request.headers = headers
|
|
|
request.proxies = self.proxy
|
|
|
|
|
|
- def detail_get(self, request, response):
|
|
|
- if self.ct > 5:
|
|
|
- return
|
|
|
+ def validate(self, request, response):
|
|
|
if response.status_code != 200:
|
|
|
- self.ct += 1
|
|
|
- self.cookies = {}
|
|
|
- self.proxy = get_proxy()
|
|
|
- yield request
|
|
|
- else:
|
|
|
- self.ct = 0
|
|
|
- items = request.item
|
|
|
- list_item = DataBakItem(**items)
|
|
|
+ raise ConnectionRefusedError
|
|
|
|
|
|
- dt = response.json.get('data')
|
|
|
- requestDto = dt.get('requestDto')
|
|
|
- requestItemList = dt.get('requestItemList')
|
|
|
+ def detail_get(self, request, response):
|
|
|
+ items = request.item
|
|
|
+ data_item = DataBakItem(**items)
|
|
|
|
|
|
- wl_html = ""
|
|
|
- if requestItemList:
|
|
|
- for info in requestItemList:
|
|
|
- temp = f'''
|
|
|
- <tr data-index="0">
|
|
|
- <td data-field="materialNo" data-key="1-0-0" align="center">
|
|
|
- <div>{info.get('materialNo','')}</div>
|
|
|
- </td>
|
|
|
- <td data-field="materialName" data-key="1-0-1" align="center">
|
|
|
- <div>{info.get('materialName','')}</div>
|
|
|
- </td>
|
|
|
- <td data-field="characters" data-key="1-0-2" align="center">
|
|
|
- <div>{info.get('characters','')}</div>
|
|
|
- </td>
|
|
|
- <td data-field="producer" data-key="1-0-3" align="center">
|
|
|
- <div>{info.get('producer','')}</div>
|
|
|
- </td>
|
|
|
- <td data-field="requestAmount" data-key="1-0-4" align="center">
|
|
|
- <div>{int(info.get('requestAmount',0))}</div>
|
|
|
- </td>
|
|
|
- <td data-field="unit" data-key="1-0-5" align="center">
|
|
|
- <div>{info.get('unit','')}</div>
|
|
|
- </td>
|
|
|
- <td data-field="requestDeliveryDate" data-key="1-0-6" align="center">
|
|
|
- <div>{ff(info.get('requestDeliveryDate',''))}</div>
|
|
|
- </td>
|
|
|
- <td data-field="memo" data-key="1-0-7" align="center">
|
|
|
- <div>{info.get('memo','')}</div>
|
|
|
- </td>
|
|
|
- </tr>
|
|
|
- '''
|
|
|
- wl_html += temp
|
|
|
+ dt = response.json.get('data')
|
|
|
+ requestDto = dt.get('requestDto')
|
|
|
+ requestItemList = dt.get('requestItemList')
|
|
|
|
|
|
- if requestDto.get('publicitySourceFlag') == 'DYLY':
|
|
|
- xjdxq = f'''
|
|
|
- <div>五、采用单一来源采购方式的原因及说明:
|
|
|
- <div>{requestDto.get('chooseSingleModeReason','无')}</div>
|
|
|
- </div>
|
|
|
- <p>六、拟定供应商:{requestDto.get('draftSupplierName','无')}</p>
|
|
|
- <p>七、公示期限:
|
|
|
- {{d.publicityTermMap.issueDate}} 至 {{d.publicityTermMap.publicityEndDate}}
|
|
|
- {ff(requestDto.get('publicityTermMap', {}).get('publicityTermMap'))} 至{ff(requestDto.get('publicityTermMap', {}).get('publicityEndDate'))}
|
|
|
- </p>
|
|
|
- <p>八、备注:{requestDto.get('memo','')}</p>
|
|
|
- '''
|
|
|
- else:
|
|
|
- xjdxq = f'''
|
|
|
- <p>五、注册资本必须大于等于{int(requestDto.get('regcapital',0))}万元</p>
|
|
|
- <p>六、报名要求:{requestDto.get('requirementDesc','')} </p>
|
|
|
- <p>七、资质要求:{requestDto.get('qualifications','')} </p>
|
|
|
- <p>八、备注:{requestDto.get('memo','')}</p></div>
|
|
|
+ wl_html = ""
|
|
|
+ if requestItemList:
|
|
|
+ for info in requestItemList:
|
|
|
+ temp = f'''
|
|
|
+ <tr data-index="0">
|
|
|
+ <td data-field="materialNo" data-key="1-0-0" align="center">
|
|
|
+ <div>{info.get('materialNo','')}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="materialName" data-key="1-0-1" align="center">
|
|
|
+ <div>{info.get('materialName','')}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="characters" data-key="1-0-2" align="center">
|
|
|
+ <div>{info.get('characters','')}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="producer" data-key="1-0-3" align="center">
|
|
|
+ <div>{info.get('producer','')}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="requestAmount" data-key="1-0-4" align="center">
|
|
|
+ <div>{int(info.get('requestAmount',0))}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="unit" data-key="1-0-5" align="center">
|
|
|
+ <div>{info.get('unit','')}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="requestDeliveryDate" data-key="1-0-6" align="center">
|
|
|
+ <div>{ff(info.get('requestDeliveryDate',''))}</div>
|
|
|
+ </td>
|
|
|
+ <td data-field="memo" data-key="1-0-7" align="center">
|
|
|
+ <div>{info.get('memo','')}</div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
'''
|
|
|
+ wl_html += temp
|
|
|
|
|
|
- html = f'''
|
|
|
- <div class="left-body">
|
|
|
- <div id="requestInfo">
|
|
|
- <div class="label-block" id="rfqMethodDiv">
|
|
|
- <span>询比价</span></div>
|
|
|
- <div id="tableRelevantDataTplDiv">
|
|
|
- <table class="timetable" id="tableRelevantData">
|
|
|
- <tbody>
|
|
|
- <tr>
|
|
|
- <td class="odd">询价单号</td>
|
|
|
- <td>{requestDto.get('ouRfqNum')}</td>
|
|
|
- <td class="odd">采购方式</td>
|
|
|
- <td>{requestDto.get('publicBiddingFlag')}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td class="odd"> 报名截止时间</td>
|
|
|
- <td>{ff(requestDto.get('registrationEndDate'))}</td>
|
|
|
- <td class="odd">报价截至时间</td>
|
|
|
- <td>{ff(requestDto.get('quotationEndDate'))}</td>
|
|
|
- </tr>
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
- </div>
|
|
|
+ if requestDto.get('publicitySourceFlag') == 'DYLY':
|
|
|
+ xjdxq = f'''
|
|
|
+ <div>五、采用单一来源采购方式的原因及说明:
|
|
|
+ <div>{requestDto.get('chooseSingleModeReason','无')}</div>
|
|
|
+ </div>
|
|
|
+ <p>六、拟定供应商:{requestDto.get('draftSupplierName','无')}</p>
|
|
|
+ <p>七、公示期限:
|
|
|
+ {{d.publicityTermMap.issueDate}} 至 {{d.publicityTermMap.publicityEndDate}}
|
|
|
+ {ff(requestDto.get('publicityTermMap', {}).get('publicityTermMap'))} 至{ff(requestDto.get('publicityTermMap', {}).get('publicityEndDate'))}
|
|
|
+ </p>
|
|
|
+ <p>八、备注:{requestDto.get('memo','')}</p>
|
|
|
+ '''
|
|
|
+ else:
|
|
|
+ xjdxq = f'''
|
|
|
+ <p>五、注册资本必须大于等于{int(requestDto.get('regcapital',0))}万元</p>
|
|
|
+ <p>六、报名要求:{requestDto.get('requirementDesc','')} </p>
|
|
|
+ <p>七、资质要求:{requestDto.get('qualifications','')} </p>
|
|
|
+ <p>八、备注:{requestDto.get('memo','')}</p></div>
|
|
|
+ '''
|
|
|
+
|
|
|
+ html = f'''
|
|
|
+ <div class="left-body">
|
|
|
+ <div id="requestInfo">
|
|
|
+ <div class="label-block" id="rfqMethodDiv">
|
|
|
+ <span>询比价</span></div>
|
|
|
+ <div id="tableRelevantDataTplDiv">
|
|
|
+ <table class="timetable" id="tableRelevantData">
|
|
|
+ <tbody>
|
|
|
+ <tr>
|
|
|
+ <td class="odd">询价单号</td>
|
|
|
+ <td>{requestDto.get('ouRfqNum')}</td>
|
|
|
+ <td class="odd">采购方式</td>
|
|
|
+ <td>{requestDto.get('publicBiddingFlag')}</td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td class="odd"> 报名截止时间</td>
|
|
|
+ <td>{ff(requestDto.get('registrationEndDate'))}</td>
|
|
|
+ <td class="odd">报价截至时间</td>
|
|
|
+ <td>{ff(requestDto.get('quotationEndDate'))}</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
</div>
|
|
|
- <div class="left-b">
|
|
|
- <div class="head-txt">
|
|
|
- <span>物料信息</span>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <table></table>
|
|
|
- <div style=" ">
|
|
|
- <div class="layui-table-box">
|
|
|
- <div class="layui-table-header">
|
|
|
- <table cellspacing="0" cellpadding="0" border="0" class="layui-table">
|
|
|
- <thead>
|
|
|
- <tr>
|
|
|
- <th style="" data-field="materialNo" data-key="1-0-0" data-unresize="true">
|
|
|
- <div align="center"><span>物料代码</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="materialName" data-key="1-0-1" data-unresize="true">
|
|
|
- <div align="center"><span>物料名称</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="characters" data-key="1-0-2" data-unresize="true">
|
|
|
- <div align="center"><span>规格型号</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="producer" data-key="1-0-3" data-unresize="true">
|
|
|
- <div align="center"><span>品牌</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="requestAmount" data-key="1-0-4" data-unresize="true">
|
|
|
- <div align="center"><span>采购数量</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="unit" data-key="1-0-5" data-unresize="true">
|
|
|
- <div align="center"><span>计量单位</span></div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="requestDeliveryDate" data-key="1-0-6" data-unresize="true"
|
|
|
- >
|
|
|
- <div align="center"><span>要求交货期</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- <th style="" data-field="memo" data-key="1-0-7" data-unresize="true">
|
|
|
- <div align="center"><span>备注</span>
|
|
|
- </div>
|
|
|
- </th>
|
|
|
- </tr>
|
|
|
- </thead>
|
|
|
- <tbody>
|
|
|
- {wl_html}
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ <div class="left-b">
|
|
|
+ <div class="head-txt">
|
|
|
+ <span>物料信息</span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <table></table>
|
|
|
+ <div style=" ">
|
|
|
+ <div class="layui-table-box">
|
|
|
+ <div class="layui-table-header">
|
|
|
+ <table cellspacing="0" cellpadding="0" border="0" class="layui-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th style="" data-field="materialNo" data-key="1-0-0" data-unresize="true">
|
|
|
+ <div align="center"><span>物料代码</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="materialName" data-key="1-0-1" data-unresize="true">
|
|
|
+ <div align="center"><span>物料名称</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="characters" data-key="1-0-2" data-unresize="true">
|
|
|
+ <div align="center"><span>规格型号</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="producer" data-key="1-0-3" data-unresize="true">
|
|
|
+ <div align="center"><span>品牌</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="requestAmount" data-key="1-0-4" data-unresize="true">
|
|
|
+ <div align="center"><span>采购数量</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="unit" data-key="1-0-5" data-unresize="true">
|
|
|
+ <div align="center"><span>计量单位</span></div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="requestDeliveryDate" data-key="1-0-6" data-unresize="true"
|
|
|
+ >
|
|
|
+ <div align="center"><span>要求交货期</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th style="" data-field="memo" data-key="1-0-7" data-unresize="true">
|
|
|
+ <div align="center"><span>备注</span>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ {wl_html}
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <div class="left-b">
|
|
|
- <div class="head-txt"><span>询单要求</span></div>
|
|
|
- <div class="inb inb-1">
|
|
|
- <div class="left-title">询价条款</div>
|
|
|
- <div class="left-content" id="termsDiv">
|
|
|
- <div class="terms"><p>一、交货地址:{requestDto.get('deliveryAddress')}</p>
|
|
|
- <p>二、保证金额度:{int(requestDto.get('assureMoney',0))}元</p>
|
|
|
- <div>三、商务条款:
|
|
|
- <div>{requestDto.get('requestBusiTerms','')}</div>
|
|
|
- </div>
|
|
|
- <div>四、技术条款:
|
|
|
- <div>{requestDto.get('requestTecTerms','')}</div>
|
|
|
- </div>
|
|
|
- {xjdxq}
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="left-b">
|
|
|
+ <div class="head-txt"><span>询单要求</span></div>
|
|
|
+ <div class="inb inb-1">
|
|
|
+ <div class="left-title">询价条款</div>
|
|
|
+ <div class="left-content" id="termsDiv">
|
|
|
+ <div class="terms"><p>一、交货地址:{requestDto.get('deliveryAddress')}</p>
|
|
|
+ <p>二、保证金额度:{int(requestDto.get('assureMoney',0))}元</p>
|
|
|
+ <div>三、商务条款:
|
|
|
+ <div>{requestDto.get('requestBusiTerms','')}</div>
|
|
|
+ </div>
|
|
|
+ <div>四、技术条款:
|
|
|
+ <div>{requestDto.get('requestTecTerms','')}</div>
|
|
|
+ </div>
|
|
|
+ {xjdxq}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- '''
|
|
|
+ </div>
|
|
|
+ '''
|
|
|
+
|
|
|
+ data_item.contenthtml = html.replace('None','')
|
|
|
|
|
|
- list_item.contenthtml = html.replace('None','')
|
|
|
+ # 附件下载需登录,暂未下载
|
|
|
+ # attachments = {}
|
|
|
+ # file_dict = response.xpath('//div[@class="left-body"]//a[@href]')
|
|
|
+ # if file_dict:
|
|
|
+ # for info in file_dict:
|
|
|
+ # file_url = info.xpath('./@href|./@data-key').extract_first("")
|
|
|
+ # file_name = info.xpath('./@href/../../../td[1]/text()').extract_first("").strip()
|
|
|
+ # if "http" not in file_url:
|
|
|
+ # file_url = "https://www.obei.com.cn" + file_url
|
|
|
+ # file_type = extract_file_type(file_name, file_url)
|
|
|
+ # if file_type:
|
|
|
+ # attachment = AttachmentDownloader().fetch_attachment(
|
|
|
+ # file_name=file_name, file_type=file_type, download_url=file_url,proxies=request.get_proxies())
|
|
|
+ # attachments[str(len(attachments) + 1)] = attachment
|
|
|
+ #
|
|
|
+ # if attachments:
|
|
|
+ # data_item.projectinfo = {"attachments": attachments}
|
|
|
|
|
|
- # 附件下载需登录,暂未下载
|
|
|
- # attachments = {}
|
|
|
- # file_dict = response.xpath('//div[@class="left-body"]//a[@href]')
|
|
|
- # if file_dict:
|
|
|
- # for info in file_dict:
|
|
|
- # file_url = info.xpath('./@href|./@data-key').extract_first("")
|
|
|
- # file_name = info.xpath('./@href/../../../td[1]/text()').extract_first("").strip()
|
|
|
- # if "http" not in file_url:
|
|
|
- # file_url = "https://www.obei.com.cn" + file_url
|
|
|
- # file_type = extract_file_type(file_name, file_url)
|
|
|
- # if file_type:
|
|
|
- # attachment = AttachmentDownloader().fetch_attachment(
|
|
|
- # file_name=file_name, file_type=file_type, download_url=file_url,proxies=request.proxies())
|
|
|
- # attachments[str(len(attachments) + 1)] = attachment
|
|
|
- #
|
|
|
- # if attachments:
|
|
|
- # list_item.projectinfo = {"attachments": attachments}
|
|
|
+ yield data_item
|
|
|
|
|
|
- yield list_item
|
|
|
+ def exception_request(self, request, response):
|
|
|
+ self.cookies = {}
|
|
|
+ self.proxy = get_proxy()
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
- Details(redis_key="lzz:obyg_dylygs").start()
|
|
|
+ Spider(redis_key="lzz:obyg_dylygs").start()
|