home.vue 129 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815
  1. <template>
  2. <div>
  3. <el-container style="height: 100vh;">
  4. <!-- #333744 -->
  5. <el-aside width="180px" style="user-select: none; border-right: 1px solid #fafafa; background-color: #333744; overflow-x: hidden;">
  6. <p class="soft-name" style="-webkit-app-region: drag; color: #fff;">
  7. <img src="../assets/image/icon.png" class="soft-icon" />
  8. <span style="letter-spacing: 1px;">{{productName}}</span>
  9. </p>
  10. <el-menu :default-openeds="['a']" :default-active="menuIndex" @select="setMenuIndex" active-text-color="#409EFF" background-color="#333744" text-color="#fff" style="margin-top: 10px;">
  11. <el-submenu index="a">
  12. <template slot="title"><img src="../assets/image/m-download.png" class="m-image"/>图片下载</template>
  13. <el-menu-item index="3">
  14. <img src="../assets/image/m-tmall.png" class="m-image"/><span slot="title">天猫</span>
  15. </el-menu-item>
  16. <el-menu-item index="2">
  17. <img src="../assets/image/m-jd.png" class="m-image"/><span slot="title">京东</span>
  18. </el-menu-item>
  19. <el-menu-item index="4">
  20. <img src="../assets/image/m-taobao.png" class="m-image"/><span slot="title">淘宝</span>
  21. </el-menu-item>
  22. <el-menu-item index="1">
  23. <img src="../assets/image/m-alibaba.png" class="m-image"/><span slot="title">阿里巴巴</span>
  24. </el-menu-item>
  25. <el-menu-item index="6">
  26. <img src="../assets/image/m-aliguoji.png" class="m-image"/><span slot="title">阿里国际</span>
  27. </el-menu-item>
  28. <el-menu-item index="9">
  29. <img src="../assets/image/m-pdd.png" class="m-image"/><span slot="title">拼多多</span>
  30. </el-menu-item>
  31. <el-menu-item index="7">
  32. <img src="../assets/image/m-baidu.png" class="m-image"/><span slot="title">百度爱采购</span>
  33. </el-menu-item>
  34. <!-- <el-menu-item index="8">
  35. <img src="../assets/image/m-amazon.png" class="m-image"/><span slot="title">亚马逊</span>
  36. </el-menu-item> -->
  37. <el-menu-item index="5">
  38. <img src="../assets/image/m-hong.png" class="m-image"/><span slot="title">小红书</span>
  39. </el-menu-item>
  40. <el-menu-item index="10">
  41. <img src="../assets/image/m-chrome.png" class="m-image"/><span slot="title">其他(Beta)</span>
  42. </el-menu-item>
  43. </el-submenu>
  44. <el-submenu index="b">
  45. <template slot="title"><img src="../assets/image/m-edit.png" class="m-image"/>图片处理</template>
  46. <el-menu-item index="2-1">
  47. <img src="../assets/image/m-geshi.png" class="m-image"/><span slot="title">格式转换</span>
  48. </el-menu-item>
  49. <el-menu-item index="2-2">
  50. <img src="../assets/image/m-yasuo.png" class="m-image"/><span slot="title">图片压缩</span>
  51. </el-menu-item>
  52. <el-menu-item index="2-3">
  53. <img src="../assets/image/m-chicun.png" class="m-image"/><span slot="title">修改尺寸</span>
  54. </el-menu-item>
  55. <el-menu-item index="2-5">
  56. <img src="../assets/image/m-shuiyin.png" class="m-image"/><span slot="title">添加水印</span>
  57. </el-menu-item>
  58. </el-submenu>
  59. </el-menu>
  60. </el-aside>
  61. <el-container>
  62. <el-header height="45px" style="background-color: #fafafa; padding: 0 10px;">
  63. <soft-header ref="headerRef" @update-soft="updateSoft()" @export-file="exportFile" @login-url="loginUrl" @clear-cache="clearCache"></soft-header>
  64. </el-header>
  65. <soft-img ref="imgRef" v-show="['2-1', '2-2', '2-3', '2-5'].indexOf(menuIndex) > -1" @open-vip="openVip" @check-authority="checkAuthority"></soft-img>
  66. <el-main v-show="['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'].indexOf(menuIndex) > -1" ref="el-main" style="background-color: #fafafa;">
  67. <template>
  68. <div class="content-top">
  69. <div>
  70. <el-button-group>
  71. <el-button type="primary" size="mini" icon="el-icon-circle-plus-outline"
  72. @click="addVisible = true; add();">添加链接</el-button>
  73. <el-button type="primary" size="mini" icon="el-icon-upload"
  74. @click="pickLink()">导入链接</el-button>
  75. <el-button type="primary" size="mini" icon="el-icon-delete"
  76. @click="clearList()">清空链接</el-button>
  77. <el-button type="danger" size="mini" icon="el-icon-video-pause" :disabled="pauseFlag"
  78. @click="pause()">任务中止</el-button>
  79. <!-- <el-button type="danger" size="mini" icon="el-icon-video-pause"
  80. @click="del()">批量删除</el-button> -->
  81. </el-button-group>
  82. <el-link type="info" style="margin-left: 10px; vertical-align:baseline; font-size: 12px;" @click="downloadExample()">导入模板<i class="el-icon-download"></i></el-link>
  83. </div>
  84. <el-row type="flex" style="align-items: center;">
  85. <div class="set-item">
  86. <span class="set-title">保存目录:</span>
  87. <el-input :title="downloadDir" ref="upload-input" size="mini" @focus="pickPath" placeholder="请选择输出目录" v-model="downloadDir" readonly style="width:200px;" prefix-icon="el-icon-folder"></el-input>
  88. <el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="打开保存目录">
  89. <i class="el-icon-folder-opened" slot="reference" style="padding-left: 5px; cursor: pointer; font-size: 22px; vertical-align: middle;" @click="openFolder()"></i>
  90. </el-popover>
  91. </div>
  92. <el-button type="danger" @click="exportFile()" :loading="loading">开始下载</el-button>
  93. </el-row>
  94. </div>
  95. <div style="padding: 20px 20px 0 20px; height: calc(100% - 62px);">
  96. <el-row type="flex" justify="space-between">
  97. <div>
  98. <h3 style="display: inline-block;">
  99. <span v-if="menuIndex == '1'">阿里巴巴 - </span>
  100. <span v-if="menuIndex == '2'">京东 - </span>
  101. <span v-if="menuIndex == '3'">天猫 - </span>
  102. <span v-if="menuIndex == '4'">淘宝 - </span>
  103. <span v-if="menuIndex == '5'">小红书 - </span>
  104. <span v-if="menuIndex == '6'">阿里国际 - </span>
  105. <span v-if="menuIndex == '7'">百度爱采购 - </span>
  106. <span v-if="menuIndex == '8'">亚马逊 - </span>
  107. <span v-if="menuIndex == '9'">拼多多 - </span>
  108. <span v-if="menuIndex == '10'">网页 - </span>
  109. 图片下载
  110. </h3>
  111. <el-link v-if="menuIndex == '5'" :underline="false" type="danger" style="text-align: center; font-size: 12px;">
  112. 仅支持win10及以上系统,浏览器请选择最新版本
  113. </el-link>
  114. <el-link v-show="menuIndex == '9'" :underline="false" type="danger" style="text-align: center; font-size: 12px;">
  115. <span id="ccc">网址:https://mobile.yangkeduo.com</span>
  116. </el-link>
  117. <el-link v-if="menuIndex == '10'" :underline="false" type="danger" style="text-align: center; font-size: 12px;">
  118. 非会员功能,仅提供测试试用
  119. </el-link>
  120. </div>
  121. </el-row>
  122. <div style="padding: 15px 0 20px;">
  123. <el-row type="flex" justify="space-between">
  124. <div v-if="menuIndex == '5'" style="padding-top: 10px;">
  125. <label>下载类型:</label>
  126. <el-checkbox-group :min="1" v-model="settingArr" style="display: inline-block;" @input="settingGroup">
  127. <el-checkbox label="mainImg">文章图</el-checkbox>
  128. <el-checkbox label="video">视频</el-checkbox>
  129. </el-checkbox-group>
  130. <!-- <el-checkbox :value="true" style="opacity: 0.6; cursor: not-allowed;">文章图/视频</el-checkbox> -->
  131. <el-popover placement="bottom" popper-class="popper-open" trigger="hover" content="实况(Live)图下载的格式是mp4视频">
  132. <i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
  133. </el-popover>
  134. </div>
  135. <div v-if="menuIndex == '10'" style="padding-top: 10px;">
  136. <label>下载类型:</label>
  137. <el-checkbox :value="true" style="opacity: 0.6; cursor: not-allowed;">图片</el-checkbox>
  138. </div>
  139. <div v-if="['1', '2', '3', '4', '6', '7', '8', '9'].indexOf(menuIndex) > -1" style="padding-top: 10px;">
  140. <label>下载类型:</label>
  141. <el-checkbox-group :min="1" v-model="settingArr" style="display: inline-block;" @input="settingGroup">
  142. <el-checkbox label="mainImg">主图</el-checkbox>
  143. <el-checkbox label="detailImg">详情图</el-checkbox>
  144. <el-checkbox label="skuImg" v-if="menuIndex != '7'">SKU图</el-checkbox>
  145. <el-checkbox label="commentImg" v-if="menuIndex == '3' || menuIndex == '4'">评论图</el-checkbox>
  146. <el-checkbox label="video">视频</el-checkbox>
  147. </el-checkbox-group>
  148. <el-popover placement="bottom" popper-class="popper-open" trigger="hover"
  149. :content="menuIndex == '9' ? '视频下载的是商品视频,非商品讲解视频' : '下载类型至少选一个,评论图默认只下载商品首页展示的评论内容'">
  150. <i class="el-icon-info" slot="reference" style="margin-left: 10px; color: #F56C6C;"></i>
  151. </el-popover>
  152. </div>
  153. <!-- 阿里巴巴账号 -->
  154. <template v-if="menuIndex == '1'">
  155. <div>
  156. <el-tag type="info" size="mini" v-if="alibabaStatus == 1">未检测</el-tag>
  157. <el-tag type="success" size="mini" v-if="alibabaStatus == 2">阿里巴巴账号已登录</el-tag>
  158. <el-link type="danger" style="text-decoration: underline;" v-if="alibabaStatus == 3" :underline="false" @click="loginUrl('https://www.1688.com')">未登录,点击登录阿里巴巴账号</el-link>
  159. <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='alibabaStatus == 2' @click="checkAlibabaLogin">检测登录状态</el-button>
  160. </div>
  161. </template>
  162. <!-- 天猫/淘宝 -->
  163. <template v-if="menuIndex == '3' || menuIndex == '4'">
  164. <div>
  165. <el-tag type="info" size="mini" v-if="tbStatus == 1">未检测</el-tag>
  166. <el-tag type="success" size="mini" v-if="tbStatus == 2">{{menuIndex == '3' ? '天猫' : '淘宝'}}账号已登录</el-tag>
  167. <el-link type="danger" style="text-decoration: underline;" v-if="tbStatus == 3" :underline="false" @click="loginUrl('https://login.taobao.com')">未登录,点击登录<span>{{menuIndex == '3' ? '天猫' : '淘宝'}}</span>账号</el-link>
  168. <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='tbStatus == 2' @click="checkLogin">检测登录状态</el-button>
  169. </div>
  170. </template>
  171. <!-- 京东账号 -->
  172. <template v-if="menuIndex == '2'">
  173. <div>
  174. <el-tag type="info" size="mini" v-if="jdStatus == 1">未检测</el-tag>
  175. <el-tag type="success" size="mini" v-if="jdStatus == 2">京东账号已登录</el-tag>
  176. <el-link type="danger" style="text-decoration: underline;" v-if="jdStatus == 3" :underline="false" @click="loginUrl('https://passport.jd.com/new/login.aspx')">未登录,点击登录京东账号</el-link>
  177. <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='jdStatus == 2' @click="checkJdLogin">检测登录状态</el-button>
  178. </div>
  179. </template>
  180. <!-- 小红书 -->
  181. <template v-if="menuIndex == '5'">
  182. <div>
  183. <el-tag type="info" size="mini" v-if="redStatus == 1">未检测</el-tag>
  184. <el-tag type="success" size="mini" v-if="redStatus == 2">小红书账号已登录</el-tag>
  185. <el-link type="danger" style="text-decoration: underline;" v-if="redStatus == 3" :underline="false" @click="loginUrl('https://www.xiaohongshu.com')">未登录,点击登录小红书账号</el-link>
  186. <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='redStatus == 2' @click="checkRedLogin">检测登录状态</el-button>
  187. </div>
  188. </template>
  189. <!-- 拼多多 -->
  190. <template v-if="menuIndex == '9'">
  191. <div>
  192. <el-tag type="info" size="mini" v-if="pddStatus == 1">未检测</el-tag>
  193. <el-tag type="success" size="mini" v-if="pddStatus == 2">拼多多账号已登录</el-tag>
  194. <el-link type="danger" style="text-decoration: underline;" v-if="pddStatus == 3" :underline="false" @click="loginUrl('https://mobile.yangkeduo.com/login.html')">未登录,点击登录拼多多账号</el-link>
  195. <el-button size="mini" type="warning" :loading="checkLoading" style="margin-left: 10px;" :disabled='pddStatus == 2' @click="checkPddLogin">检测登录状态</el-button>
  196. </div>
  197. </template>
  198. </el-row>
  199. </div>
  200. <div class="table-scroll">
  201. <!-- 1、 -->
  202. <vxe-table ref="xTable" show-overflow class="img-table" max-height="100%" empty-text="没有更多数据了!" :loading="tabLoading" :row-config="{isHover: true}"
  203. :loading-config="{icon: 'vxe-icon-indicator roll', text: '列表加载中...'}" :data="this[listStr+'List']" :scroll-y="{enabled: true}">
  204. <!-- <vxe-column type="checkbox" width="40"></vxe-column> -->
  205. <vxe-column type="seq" width="60"></vxe-column>
  206. <vxe-column field="title" title="目录名称" width="180">
  207. <template #default="{ row, rowIndex }">
  208. <span v-if="row.title">{{row.title}}</span>
  209. <el-tag size="mini" v-else>默认使用网页标题</el-tag>
  210. </template>
  211. </vxe-column>
  212. <vxe-column field="url" title="网页链接"></vxe-column>
  213. <vxe-column field="status" title="下载状态" width="200">
  214. <template #default="{ row }">
  215. <template v-if="row.status == '1'">
  216. <i class="el-icon-info" style="font-size: 16px; color: #999;"></i>
  217. <span>待操作</span>
  218. </template>
  219. <template v-if="row.status == '2'">
  220. <i class="el-icon-loading" style="font-size: 16px; color: #999;"></i>
  221. <span>任务处理中...</span>
  222. </template>
  223. <template v-if="row.status == '3'">
  224. <i class="el-icon-loading" style="font-size: 16px; color: #999;"></i>
  225. <span>图片下载中..<span v-if="row.num > 0">第{{row.num}}张</span></span>
  226. </template>
  227. <template v-if="row.status == '4'">
  228. <i class="el-icon-success" style="font-size: 16px; color: #19be6b;"></i>
  229. <span>下载完成</span>
  230. </template>
  231. <template v-if="row.status == '5'">
  232. <i class="el-icon-error" style="font-size: 16px; color: #ed4014;"></i>
  233. <span>网络异常,请重试!</span>
  234. </template>
  235. <template v-if="row.status == '6'">
  236. <i class="el-icon-error" style="font-size: 16px; color: #ed4014;"></i>
  237. <span>验证码拦截,请手动验证!</span>
  238. </template>
  239. <template v-if="row.status == '7'">
  240. <i class="el-icon-error" style="font-size: 16px; color: #ed4014;"></i>
  241. <span>频繁访问受限,清除缓存重试</span>
  242. </template>
  243. </template>
  244. </vxe-column>
  245. <vxe-column title="操作" width="80">
  246. <template #default="{ row, rowIndex }">
  247. <i class="el-icon-delete cur-pointer" style="font-size: 20px;" @click="delFile(rowIndex)"></i>
  248. </template>
  249. </vxe-column>
  250. </vxe-table>
  251. </div>
  252. </div>
  253. </template>
  254. <el-dialog title="添加链接" :visible.sync="addVisible" width="500px" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
  255. <div>
  256. <el-form label-position="right" label-width="80px" :rules="rules" :model="formData" ref="formData">
  257. <el-form-item label="目录名称" prop="title">
  258. <el-input id="aaa" v-model="formData.title" placeholder="为空则默认使用网页标题前50个字符"></el-input>
  259. </el-form-item>
  260. <el-form-item label="网页链接" prop="url">
  261. <el-input id="bbb" type="textarea" :rows="10" :placeholder="'请输入网址链接(例:' + exampleUrl[menuIndex-1] + ')'" v-model="formData.url"></el-input>
  262. </el-form-item>
  263. </el-form>
  264. </div>
  265. <span slot="footer" class="dialog-footer">
  266. <el-button @click="addVisible = false; $refs['formData'].resetFields();">取 消</el-button>
  267. <el-button type="primary" @click="onSubmit">确 定</el-button>
  268. </span>
  269. </el-dialog>
  270. <el-dialog title="提示" :visible.sync="loginVisible" width="400px" :close-on-click-modal="false" :close-on-press-escape="false">
  271. <div style="text-align: center; color: #999; font-size: 14px;">
  272. <template v-if="menuIndex == '1'">
  273. <p>阿里巴巴渠道建议登录后下载</p>
  274. <p class="visible-tips-style">目前检测还未登录阿里巴巴账号,未登录可能会导致图片下载不全</p>
  275. </template>
  276. <template v-else-if="menuIndex == '2'">
  277. <p>京东渠道需要登录后才能下载</p>
  278. <p class="visible-tips-style">目前检测还未登录京东账号,需立即登录</p>
  279. </template>
  280. <template v-else-if="menuIndex == '5'">
  281. <p>小红书渠道需要登录后才能下载</p>
  282. <p class="visible-tips-style">目前检测还未登录小红书账号,需立即登录</p>
  283. </template>
  284. <template v-else-if="menuIndex == '9'">
  285. <p>拼多多渠道需要登录后才能下载</p>
  286. <p class="visible-tips-style">目前检测还未登录拼多多账号,需立即登录</p>
  287. </template>
  288. <template v-else>
  289. <p>天猫/淘宝渠道需要登录后才能下载</p>
  290. <p class="visible-tips-style">目前检测还未登录天猫/淘宝账号,需立即登录</p>
  291. </template>
  292. </div>
  293. <div slot="footer" class="dialog-footer-center">
  294. <el-button v-if="menuIndex == '2'" @click="loginVisible = false; loginUrl('https://passport.jd.com/new/login.aspx')">点击登录京东账号</el-button>
  295. <template v-else-if="menuIndex == '1'">
  296. <el-button @click="loginVisible = false; loginUrl('https://www.1688.com')">点击登录阿里巴巴账号</el-button>
  297. <el-button type="primary" @click="loginVisible = false; skipLogin = true; exportFile();">继续下载</el-button>
  298. </template>
  299. <el-button v-else-if="menuIndex == '5'" @click="loginVisible = false; loginUrl('https://www.xiaohongshu.com')">点击登录小红书账号</el-button>
  300. <el-button v-else-if="menuIndex == '9'" @click="loginVisible = false; loginUrl('https://mobile.yangkeduo.com/login.html')">点击登录拼多多账号</el-button>
  301. <el-button v-else @click="loginVisible = false; loginUrl('https://login.taobao.com')">点击登录天猫/淘宝账号</el-button>
  302. </div>
  303. </el-dialog>
  304. <!-- 非会员转换提示框 -->
  305. <el-dialog title="非会员提示" :visible.sync="tipsModal" width="400px">
  306. <div class="member-model">
  307. <div class="tips-flex">
  308. <i class="el-icon-s-opportunity"></i>
  309. <p class="m-title">{{tipsDesc}}</p>
  310. </div>
  311. <div class="member-btn">
  312. <el-button size="small" round type="primary" @click="openVip()">开通会员</el-button>
  313. </div>
  314. </div>
  315. </el-dialog>
  316. </el-main>
  317. <el-footer height="48px">
  318. <!-- 更新 -->
  319. <soft-update ref="updateRef" :showDowload="dowloadModel" :dowloadFinish="finishModel"></soft-update>
  320. </el-footer>
  321. </el-container>
  322. </el-container>
  323. </div>
  324. </template>
  325. <script>
  326. import os from 'os'
  327. import fs from 'fs'
  328. import request from 'request'
  329. import path from 'path';
  330. import xlsx from 'node-xlsx';
  331. import softUpdate from './update.vue';
  332. import softHeader from './header.vue';
  333. import softImg from './img.vue';
  334. import electronApi from '@/utils/electronApi';
  335. import pjson from '/package.json'
  336. // import puppeteer from 'puppeteer'
  337. import puppeteer from 'puppeteer-extra'
  338. const StealthPlugin = require('puppeteer-extra-plugin-stealth');
  339. const listNameArr = ['alibaba','jd','tmall','tb','red','aliguoji','acaigou','amazon', 'pdd' ,'common'];
  340. // const headless = true;
  341. // const waitUntil = 'networkidle2';
  342. const { ipcRenderer } = require('electron');
  343. //const chromePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
  344. let separator = '';
  345. if (os.platform == 'linux') {
  346. separator = '/'
  347. } else {
  348. separator = '\\'
  349. }
  350. // let chromePath = process.cwd() + '\\resources\\app\\node_modules\\puppeteer\\.local-chromium\\win64-1045629\\chrome-win\\chrome.exe';
  351. // if (process.env.NODE_ENV == 'development') {
  352. // chromePath = process.cwd() + '\\node_modules\\puppeteer\\.local-chromium\\win64-1045629\\chrome-win\\chrome.exe';
  353. // }
  354. export default {
  355. name: 'landing-page',
  356. components: {
  357. softUpdate,
  358. softHeader,
  359. softImg
  360. },
  361. data() {
  362. return {
  363. tipsModal: false,
  364. tipsDesc: "非VIP用户不能下载视频,如需完整功能请开通VIP会员。",
  365. settingArr: ['mainImg'],
  366. loginVisible: false,
  367. addVisible: false,
  368. formData: {
  369. title: '',
  370. url: ''
  371. },
  372. rules:{ //
  373. title: [
  374. { min: 0, max: 50, message: '不能超过 50 个字符', trigger: 'blur' },
  375. { pattern: /^[^\\/:*?"<>|]*$/, message: '标题中不能包含 \\ / : * ? " < > |', trigger: 'blur' }
  376. ],
  377. url: [
  378. { required: true, message: '请输入网页链接', trigger: 'blur' },
  379. { pattern: /^(http|https):\/\/.+$/, message: '请输入正确的网址链接(http://或https://开头),结尾不能有换行符', trigger: 'blur' }
  380. ],
  381. },
  382. tabLoading: false,
  383. alibabaList: [],
  384. aliguojiList: [],
  385. amazonList: [],
  386. acaigouList: [],
  387. jdList: [],
  388. tbList: [],
  389. tmallList: [],
  390. redList: [],
  391. pddList: [],
  392. commonList: [],
  393. productName: pjson.softInfo.softName,
  394. imgUrl: this.$api.imgUrl,
  395. imgSrc: '',
  396. menuIndex: '3',
  397. settingData: {
  398. detailImg: true,
  399. skuImg: true,
  400. commentImg: false,
  401. video: false,
  402. },
  403. exampleUrl: ['https://www.1688.com', 'https://www.jd.com', 'https://www.tmall.com', 'https://www.taobao.com', 'https://www.xiaohongshu.com',
  404. 'https://www.alibaba.com', 'https://b2b.baidu.com', 'https://www.amazon.com', 'https://mobile.yangkeduo.com/goods.html', 'https://www.example.com'],
  405. fileList: [],
  406. downloadDir: os.userInfo().homedir + separator + "Downloads",
  407. dowloadModel: false,
  408. finishModel: false,
  409. loading: false,
  410. checkLoading: false, //点击检测登录状态
  411. tbStatus: 1, // 1、未检测 2、已经登录 3、未登录
  412. jdStatus: 1, // 1、未检测 2、已经登录 3、未登录
  413. redStatus: 1, //同上
  414. alibabaStatus: 1, //同上上
  415. aliguojiStatus: 1, //同上上上
  416. pddStatus: 1,
  417. execLimit: 1,
  418. execNum: 3, // 限制5张
  419. /** 浏览器名称 **/
  420. alibabaBrowser: null,
  421. aliguojiBrowser: null,
  422. amazonBrowser: null,
  423. acaigouBrowser: null,
  424. tbBrowser: null,
  425. jdBrowser: null,
  426. commonBrowser: null,
  427. redBrowser: null,
  428. pddBrowser: null,
  429. loginBrowser: null, // 登录用的浏览器实例
  430. skipLogin: false,
  431. pauseFlag: true, //暂停中止标志
  432. rightClick: false, // 右击事件绑定
  433. };
  434. },
  435. computed: {
  436. listStr: function(){
  437. let index = Number(this.menuIndex) - 1;
  438. return listNameArr[index];
  439. }
  440. },
  441. async mounted() {
  442. this.$refs.updateRef.updateSoft(true);
  443. let homedir = os.userInfo().homedir;
  444. if (fs.existsSync(homedir + separator + "Desktop")) {
  445. this.downloadDir = homedir + separator + "Desktop"
  446. } else {
  447. this.downloadDir = homedir + separator + "Downloads"
  448. }
  449. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
  450. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
  451. }
  452. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
  453. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
  454. }
  455. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
  456. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
  457. }
  458. let path = os.tmpdir() + separator + 'chrome-data-capture';
  459. let path2 = os.tmpdir() + separator + 'chrome-data-capture-jd';
  460. //this.deleteAll(path, false);
  461. //this.deleteAll(path2, false);
  462. // 打开浏览器
  463. const {
  464. shell
  465. } = require('electron');
  466. const links = document.querySelectorAll('a[href]');
  467. links.forEach(link => {
  468. link.addEventListener('click', e => {
  469. const url = link.getAttribute('href');
  470. e.preventDefault();
  471. shell.openExternal(url);
  472. });
  473. });
  474. // 判断系统版本 低于10使用兼容模式
  475. if(os.release() && os.release().indexOf('.') > -1){
  476. let systemVersion = Number(os.release().split('.')[0]);
  477. if(systemVersion < 10){ // 低于win10,软件打开时候浏览器设置为兼容版
  478. this.$utils.setStorage('versionType', 1);
  479. }else{
  480. this.$utils.setStorage('versionType', 2);
  481. }
  482. }
  483. // 初始化开发者设置
  484. this.$utils.setStorage('headless', 1);
  485. this.$utils.setStorage('waitUntil', 'networkidle2');
  486. document.getElementById('ccc').addEventListener('contextmenu', e => {
  487. e.preventDefault();
  488. // 发送事件到主进程,附带元素类型信息
  489. ipcRenderer.send('show-context-menu', 'span');
  490. });
  491. },
  492. methods: {
  493. add(){
  494. if(!this.rightClick){
  495. setTimeout(() => {
  496. document.getElementById('aaa').addEventListener('contextmenu', e => {
  497. e.preventDefault();
  498. // 发送事件到主进程,附带元素类型信息
  499. ipcRenderer.send('show-context-menu', 'input');
  500. });
  501. document.getElementById('bbb').addEventListener('contextmenu', e => {
  502. e.preventDefault();
  503. // 发送事件到主进程,附带元素类型信息
  504. ipcRenderer.send('show-context-menu', 'input');
  505. });
  506. }, 800)
  507. this.rightClick = true;
  508. }
  509. },
  510. // 实时获取浏览器路径
  511. initPath(){
  512. let chromeType = this.$utils.getStorage('chromeType');
  513. let chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
  514. if(chromeType == 1){ // 电脑自带浏览器
  515. chromePath = this.$utils.getStorage('chromePath');
  516. }else{
  517. chromePath = puppeteer.executablePath().replace('win32-1', 'win64-1');
  518. let versionType = this.$utils.getStorage('versionType');
  519. if(versionType && versionType == 1){
  520. chromePath = chromePath.replace('chrome-win', 'chrome7');
  521. }
  522. }
  523. return chromePath;
  524. },
  525. // 实时获取浏览器数据缓存
  526. initDataDir(tag){
  527. let chromeType = this.$utils.getStorage('chromeType');
  528. let userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
  529. if(chromeType == 1){ // 电脑自带浏览器
  530. userDataDir = os.tmpdir() + separator + 'chrome-data-capture-local';
  531. }else{
  532. userDataDir = os.tmpdir() + separator + 'chrome-data-capture';
  533. if(tag == 'jd'){
  534. userDataDir = os.tmpdir() + separator + 'chrome-data-capture-jd';
  535. }
  536. }
  537. return userDataDir;
  538. },
  539. // 实时获取页面滚动加载时间
  540. initMs(){
  541. let pageMs = this.$utils.getStorage('pageMs');
  542. if(pageMs){
  543. return Number(pageMs);
  544. }else{
  545. return 500;
  546. }
  547. },
  548. // 实时获取淘宝的开发者设置
  549. initDevelop(){
  550. let develop = {
  551. headless: true,
  552. waitUntil: 'networkidle2'
  553. };
  554. let n1 = this.$utils.getStorage('headless');
  555. let n2 = this.$utils.getStorage('waitUntil');
  556. if(n1){
  557. if(n1 == 1){
  558. develop.headless = true;
  559. }else if(n1 == 2){
  560. develop.headless = false;
  561. }
  562. }
  563. if(n2){
  564. develop.waitUntil = n2;
  565. }
  566. return develop;
  567. },
  568. // 删除文件夹内容
  569. deleteAll(folderPath, flag) {
  570. if (fs.existsSync(folderPath)) {
  571. fs.readdirSync(folderPath).forEach((file, index) => {
  572. var curPath = path.join(folderPath, file);
  573. if (fs.lstatSync(curPath).isDirectory()) {
  574. this.deleteAll(curPath, true);
  575. } else {
  576. fs.unlinkSync(curPath);
  577. }
  578. });
  579. if(flag){
  580. fs.rmdirSync(folderPath);
  581. }
  582. }
  583. },
  584. checkAuthority(){
  585. let authority = this.$refs.headerRef.authority;
  586. this.$refs.imgRef.authority = authority;
  587. },
  588. setMenuIndex(index){
  589. this.menuIndex = index;
  590. if(index.indexOf('2-') > -1){
  591. let num = Number(index.split('-')[1]);
  592. this.$refs.imgRef.setMenuIndex(num);
  593. }
  594. },
  595. // 选择目录
  596. pickPath() {
  597. this.$refs['upload-input'].blur();
  598. electronApi.call('pickDir', []).then((path) => {
  599. if (path) {
  600. this.downloadDir = path;
  601. }
  602. });
  603. },
  604. // 打开自定义下载目录
  605. openFolder() {
  606. let path = this.downloadDir;
  607. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
  608. path = this.downloadDir + separator + pjson.softInfo.softName;
  609. } else {
  610. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
  611. path = this.downloadDir + separator + pjson.softInfo.softName;
  612. }
  613. electronApi.call('showItemInfolder', [path + '\\tty.tty'])
  614. },
  615. openVip() {
  616. this.$refs.headerRef.openVip();
  617. },
  618. updateSoft() {
  619. this.$refs.updateRef.updateSoft();
  620. },
  621. // 删除文件
  622. delFile(rowIndex){
  623. let index = Number(this.menuIndex) - 1;
  624. let type = listNameArr[index];
  625. this.$confirm('确认删除此行数据吗?', '提示', {
  626. confirmButtonText: '确定',
  627. cancelButtonText: '取消',
  628. type: 'warning'
  629. }).then(() => {
  630. this[type+'List'].splice(rowIndex, 1);
  631. if(this[type+'List'].length == 0) {
  632. this.clearList();
  633. }
  634. }).catch(() => {
  635. });
  636. },
  637. // 清除列表
  638. clearList() {
  639. let index = Number(this.menuIndex) - 1;
  640. this[listNameArr[index]+'List'] = [];
  641. },
  642. // 提交表单
  643. onSubmit(){
  644. this.$refs['formData'].validate((valid) => {
  645. if (valid) {
  646. let info = {
  647. url: this.formData.url,
  648. title: this.formData.title,
  649. status: '1',
  650. num: 0,
  651. newPath: ''
  652. }
  653. let index = Number(this.menuIndex) - 1;
  654. this[listNameArr[index]+'List'].push(info);
  655. this.$refs['formData'].resetFields();
  656. this.addVisible = false;
  657. } else {
  658. return false;
  659. }
  660. });
  661. },
  662. async pickLink() { // 导入链接
  663. const spinLoad = this.$loading();
  664. await electronApi.call('pickFile', ['xlsx,xls', true]).then(async (path) => {
  665. spinLoad.close();
  666. if(path.length > 0){
  667. this.$notify({
  668. title: '提示',
  669. message: '导入成功',
  670. type: 'success'
  671. });
  672. let workSheetsFromBuffer = xlsx.parse(fs.readFileSync(path[0]));
  673. if(workSheetsFromBuffer && workSheetsFromBuffer.length > 0){
  674. let errMsg = "";
  675. workSheetsFromBuffer[0].data.map((item, index) => {
  676. if(item.length > 0){
  677. let ititle = '';
  678. if(item[0]){
  679. ititle = item[0].toString().trim();
  680. }
  681. if(item[0] == '目录名称' && item[1] == '网页链接'){
  682. return false;
  683. }
  684. if(this.containsAnyChar(ititle.toString(), ['\\', '/', ':', '*', '?', '"', '<', '>', '|'])){ //判断是否含有特殊字符
  685. errMsg += "第" + (index+1) + '行-名称不能包以下字符 \\ / : * ? " < > |';
  686. ititle = ititle.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
  687. }
  688. if(item[1] == undefined){
  689. errMsg += "第" + (index+1) + "行格式有误</br>";
  690. item[1] = '';
  691. }else if(!/^(http|https):\/\/.+$/.exec(item[1])){
  692. errMsg += "第" + (index+1) + "行网址格式有误</br>";
  693. }else{
  694. let info = {
  695. url: item[1],
  696. title: ititle,
  697. status: '1',
  698. num: 0,
  699. newPath: ''
  700. }
  701. let key = Number(this.menuIndex) - 1;
  702. this[listNameArr[key]+'List'].push(info);
  703. }
  704. }
  705. });
  706. if(errMsg){
  707. this.$notify({
  708. title: '请检查文件以下问题',
  709. dangerouslyUseHTMLString: true,
  710. message: errMsg,
  711. type: 'warning'
  712. });
  713. }
  714. }else{
  715. this.$notify({
  716. title: '提示',
  717. message: '格式有误,请重新导入',
  718. type: 'warning'
  719. });
  720. }
  721. }
  722. });
  723. },
  724. settingGroup(name){
  725. let authority = this.$refs.headerRef.authority.isAuthority;
  726. let index = name.indexOf('video');
  727. if(index > -1 && !authority){ // 非会员选中下载视频选项-提示
  728. this.tipsModal = true;
  729. name.splice(index, 1);
  730. }
  731. },
  732. // 清除缓存的后续操作
  733. async clearCache(){
  734. this.jdStatus = 3;
  735. this.tbStatus = 3;
  736. this.redStatus = 3;
  737. this.alibabaStatus = 3;
  738. this.aliguojiStatus = 3;
  739. this.pddStatus = 3;
  740. if(this.loginBrowser){
  741. await this.loginBrowser.close();
  742. this.loginBrowser = null;
  743. }
  744. for(let i = 0; i < listNameArr.length; i++){
  745. if(listNameArr[i]){
  746. if(this[listNameArr[i]+'Browser']){
  747. await this[listNameArr[i]+'Browser'].close();
  748. this[listNameArr[i]+'Browser'] = null;
  749. }
  750. }
  751. }
  752. },
  753. // 去登录
  754. loginUrl(url){
  755. (async () => {
  756. try{
  757. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture')) {
  758. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture');
  759. }
  760. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-jd')) {
  761. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-jd');
  762. }
  763. if (!fs.existsSync(os.tmpdir() + separator + 'chrome-data-capture-local')) {
  764. fs.mkdirSync(os.tmpdir() + separator + 'chrome-data-capture-local');
  765. }
  766. let userDataDir = this.initDataDir();
  767. if(url.indexOf('.jd.com/') > -1){
  768. userDataDir = this.initDataDir('jd');
  769. }
  770. puppeteer.use(StealthPlugin());
  771. this.loginBrowser = await puppeteer.launch({
  772. headless: false,
  773. executablePath: this.initPath(),
  774. args: ['--window-size=1280,800'],
  775. userDataDir: userDataDir,
  776. });
  777. const page = await this.loginBrowser.newPage();
  778. await page.setViewport({ width: 1280, height: 800 });
  779. await page.evaluateOnNewDocument(() => {
  780. const newProto = navigator.__proto__;
  781. delete newProto.webdriver;
  782. navigator.__proto__ = newProto;
  783. window.navigator.chrome = {
  784. runtime: {}
  785. };
  786. });
  787. await page.goto(url, {waitUntil : 'networkidle2'});
  788. }catch(e){
  789. this.showError(e);
  790. }
  791. })();
  792. },
  793. del(){
  794. let info = this.$refs.xTable.getCheckboxRecords();
  795. console.log(info);
  796. },
  797. //任务暂停
  798. async pause(){
  799. this.$confirm('是否中止下载任务?', '提示', {
  800. confirmButtonText: '确定',
  801. cancelButtonText: '取消',
  802. type: 'warning'
  803. }).then(async() => {
  804. if(this.loginBrowser){
  805. await this.loginBrowser.close();
  806. this.loginBrowser = null;
  807. }
  808. this.pauseFlag = true;
  809. for(let i = 0; i < listNameArr.length; i++){
  810. if(listNameArr[i]){
  811. if(this[listNameArr[i]+'Browser']){
  812. await this[listNameArr[i]+'Browser'].close();
  813. this[listNameArr[i]+'Browser'] = null;
  814. }
  815. }
  816. }
  817. let index = Number(this.menuIndex) - 1;
  818. this[listNameArr[index]+'List'].map(item => {
  819. if(item.status != '4'){
  820. item.status = '1';
  821. }
  822. });
  823. }).catch(() => {
  824. });
  825. },
  826. // 开始下载
  827. async exportFile(flag) {
  828. this.pauseFlag = false;
  829. if(this.loginBrowser){
  830. await this.loginBrowser.close();
  831. this.loginBrowser = null;
  832. }
  833. let authority = this.$refs.headerRef.authority.isAuthority;
  834. if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
  835. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
  836. }
  837. let index = Number(this.menuIndex) - 1;
  838. let fileList = this[listNameArr[index]+'List'];
  839. if(fileList.length > 0){
  840. if (!authority && !flag) { // 非会员点击转换弹出提示框
  841. this.$refs.headerRef.memberModel = true;
  842. this.$refs.headerRef.isClick = true;
  843. return false;
  844. } else {
  845. this.$refs.headerRef.memberModel = false;
  846. this.loading = true;
  847. setTimeout(() => {
  848. this.loading = false;
  849. }, 60000);
  850. }
  851. if(this.menuIndex == '1' && !this.skipLogin){ // 阿里巴巴
  852. if(this.alibabaStatus == 1 || this.alibabaStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
  853. await this.checkAlibabaLogin().then((data) => {
  854. if(data != 2){ // 未登录
  855. this.alibabaStatus = 3;
  856. this.loginVisible = true;
  857. }
  858. }).catch(err => {
  859. this.alibabaStatus = 3;
  860. });
  861. if(this.alibabaStatus == 3){
  862. this.loading = false;
  863. return false;
  864. }
  865. }
  866. }
  867. if(this.menuIndex == '2'){ // 京东
  868. if(this.jdStatus == 1 || this.jdStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
  869. await this.checkJdLogin().then((data) => {
  870. if(data != 2){ // 未登录
  871. this.jdStatus = 3;
  872. this.loginVisible = true;
  873. }
  874. }).catch(err => {
  875. this.jdStatus = 3;
  876. });
  877. if(this.jdStatus == 3){
  878. this.loading = false;
  879. return false;
  880. }
  881. }
  882. }
  883. if(this.menuIndex == '3' || this.menuIndex == '4'){ // 天猫/淘宝
  884. if(this.tbStatus == 1 || this.tbStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
  885. await this.checkLogin().then((data) => {
  886. if(data != 2){ // 未登录
  887. this.tbStatus = 3;
  888. this.loginVisible = true;
  889. }
  890. }).catch(err => {
  891. this.tbStatus = 3;
  892. });
  893. }
  894. if(this.tbStatus == 3){
  895. this.loading = false;
  896. return false;
  897. }
  898. }
  899. if(this.menuIndex == '5'){ // 小红书
  900. if(this.redStatus == 1 || this.redStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
  901. await this.checkRedLogin().then((data) => {
  902. if(data != 2){ // 未登录
  903. this.redStatus = 3;
  904. this.loginVisible = true;
  905. }
  906. }).catch(err => {
  907. this.redStatus = 3;
  908. });
  909. if(this.redStatus == 3){
  910. this.loading = false;
  911. return false;
  912. }
  913. }
  914. }
  915. if(this.menuIndex == '9'){ // 拼多多
  916. if(this.pddStatus == 1 || this.pddStatus == 3){ // 未检测登录状态/或提示未登录状态,开始检测
  917. await this.checkPddLogin().then((data) => {
  918. if(data != 2){ // 未登录
  919. this.pddStatus = 3;
  920. this.loginVisible = true;
  921. }
  922. }).catch(err => {
  923. this.pddStatus = 3;
  924. });
  925. if(this.pddStatus == 3){
  926. this.loading = false;
  927. return false;
  928. }
  929. }
  930. }
  931. let taskArr = [];
  932. let task = "";
  933. let userDataDir = this.initDataDir();
  934. if(this.menuIndex == '2'){
  935. userDataDir = this.initDataDir('jd');
  936. }
  937. // 运行不同平台的浏览器
  938. puppeteer.use(StealthPlugin());
  939. let browserName = listNameArr[index] + 'Browser';
  940. if(index == '2'){ // 天猫和淘宝共用一个
  941. browserName = 'tbBrowser';
  942. }
  943. let headless = true;
  944. headless = this.initDevelop().headless;
  945. let redSize = '';
  946. if(this.menuIndex == '5'){
  947. redSize = '--window-size=1280,800'; //给浏览器一个初始大小,在无头模式下,页面会自适用缩放
  948. }
  949. this[browserName] = await puppeteer.launch({
  950. headless: headless,
  951. executablePath: this.initPath(),
  952. userDataDir: userDataDir,
  953. args: [
  954. '--start-maximized',
  955. '--no-sandbox',
  956. '--disable-setuid-sandbox',
  957. '--disable-blink-features=AutomationControlled',
  958. redSize
  959. ]
  960. });
  961. for(let i = 0; i < fileList.length; i++){
  962. let item = fileList[i];
  963. switch(this.menuIndex){
  964. case '1': // 阿里巴巴
  965. task = this.alibabaDownload(item, this.alibabaBrowser);
  966. break;
  967. case '2': // 京东
  968. task = this.jdScanImg(item, this.jdBrowser);
  969. break;
  970. case '3': // 天猫
  971. case '4': // 淘宝
  972. task = this.tbScanImg(item, this.tbBrowser);
  973. break;
  974. case '5': // 小红书
  975. task = this.redDownload(item, this.redBrowser);
  976. break;
  977. case '6': // 阿里国际
  978. task = this.alibabaDownload(item, this.aliguojiBrowser);
  979. break;
  980. case '7': // 百度爱采购
  981. task = this.alibabaDownload(item, this.acaigouBrowser);
  982. break;
  983. case '8': // 亚马逊
  984. task = this.alibabaDownload(item, this.amazonBrowser);
  985. break;
  986. case '9': // 拼多多
  987. task = this.pddDownload(item, this.pddBrowser);
  988. break;
  989. case '10': // 普通网址
  990. task = this.normalDownload(item, this.commonBrowser);
  991. break;
  992. }
  993. if(this.pauseFlag){ //暂停跳出循环
  994. break;
  995. }
  996. if(task){
  997. taskArr.push(task);
  998. }
  999. if((i+1) % this.execLimit == 0){
  1000. await Promise.all(taskArr).then(result => {
  1001. taskArr = [];
  1002. }).catch(err => {
  1003. console.log('err'+i, err)
  1004. })
  1005. }
  1006. }
  1007. if(taskArr.length > 0){
  1008. await Promise.all(taskArr).then(result => {
  1009. taskArr = [];
  1010. }).catch(err => {
  1011. // 错误文件添加到服务中
  1012. console.log('err',err)
  1013. })
  1014. }
  1015. if(this[browserName]){
  1016. this[browserName].close();
  1017. this[browserName] = null;
  1018. }
  1019. this.loading = false;
  1020. // 打开文件夹
  1021. if(fileList.length > 0){
  1022. this.$message({message: '恭喜你,任务已完成!', type: 'success'});
  1023. electronApi.call('showItemInfolder',[this.downloadDir + separator + pjson.softInfo.softName +'\\tty.tty'])
  1024. }
  1025. }
  1026. },
  1027. // 10-普通网址下载
  1028. async normalDownload(urlInfo, commonBrowser){
  1029. let task = await new Promise((resolve,reject) =>{
  1030. (async () => {
  1031. try{
  1032. let authority = this.$refs.headerRef.authority.isAuthority;
  1033. let number = 0;
  1034. urlInfo.status = '2';
  1035. urlInfo.num = 0;
  1036. const page = await commonBrowser.newPage();
  1037. let titleFlag = true;
  1038. page.on('response', async(response) => {
  1039. if(titleFlag){ // 第一次生成页面标题
  1040. if(urlInfo.title){
  1041. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  1042. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1043. } else {
  1044. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  1045. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1046. }
  1047. }else{
  1048. await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
  1049. }
  1050. titleFlag = false;
  1051. }
  1052. // 检查响应的 MIME 类型是否以 'image/' 开头
  1053. let flag = false;
  1054. if(response.headers()['content-encoding'] && response.headers()['content-encoding'].indexOf('gzip') > -1){
  1055. flag = true;
  1056. }
  1057. if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('image/') && (flag || response.headers()['content-length'])) {
  1058. let imgArr = ['gif', 'jpeg', 'png', 'webp', 'svg', 'tiff', 'bmp', 'ico', 'avif'];
  1059. let imgType = 'jpg';
  1060. let isBase = false;
  1061. imgArr.map((item, index) => {
  1062. if(response.headers()['content-type'].indexOf(item) > -1){
  1063. imgType = item;
  1064. if(item == 'jpeg'){
  1065. imgType = 'jpg';
  1066. }else if(item == 'avif'){
  1067. imgType = 'png';
  1068. }
  1069. }
  1070. });
  1071. let url = response.url();
  1072. let regex = /^data:image\/[\w|+|-]+;base64,/;
  1073. if(regex.exec(url)){
  1074. url = response.url().replace(/^data:image\/[\w|+|-]+;base64,/, '');
  1075. isBase = true;
  1076. }
  1077. let imgInfo = {
  1078. url: url,
  1079. contentType: response.headers()['content-type'],
  1080. status: response.status(),
  1081. imgType: imgType,
  1082. isBase: isBase
  1083. }
  1084. let outputPath = urlInfo.newPath + '\\' + this.randomString(35) + '.' + imgInfo.imgType;
  1085. urlInfo.status = '3';
  1086. number++;
  1087. if(!authority && number <= this.execNum){
  1088. if(imgInfo.isBase){ //base64位图片下载
  1089. this.downloadBaseImage(imgInfo.url, outputPath, urlInfo)
  1090. }else{
  1091. this.downloadImage(imgInfo.url, outputPath, urlInfo);
  1092. }
  1093. }
  1094. if(authority){
  1095. if(imgInfo.isBase){ //base64位图片下载
  1096. this.downloadBaseImage(imgInfo.url, outputPath, urlInfo)
  1097. }else{
  1098. this.downloadImage(imgInfo.url, outputPath, urlInfo);
  1099. }
  1100. }
  1101. }
  1102. });
  1103. await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
  1104. let pageInfo = await page.evaluate(() => {
  1105. let cHeight = document.documentElement.clientHeight;
  1106. let scrollHeight = document.body.scrollHeight;
  1107. return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
  1108. });
  1109. let scrollHeight = pageInfo.scrollHeight;
  1110. let cHeight = pageInfo.cHeight;
  1111. let num = Math.ceil(scrollHeight / cHeight);
  1112. let start = -1;
  1113. let scrollTime = this.initMs();
  1114. let scrollInt = setInterval(async() => {
  1115. start ++;
  1116. await page.evaluate((start) => {
  1117. let cHeight = document.documentElement.clientHeight;
  1118. window.scrollTo({
  1119. top: cHeight * start,
  1120. behavior: "smooth"
  1121. });
  1122. }, start);
  1123. if(start > num || start > 200){ // 防止页面过长,滚动200次自动停止
  1124. clearInterval(scrollInt);
  1125. await page.close();
  1126. urlInfo.status = '4';
  1127. resolve(true);
  1128. this.loading = false;
  1129. }
  1130. }, scrollTime);
  1131. }catch(e){
  1132. urlInfo.status = '5';
  1133. reject(e);
  1134. this.showError(e);
  1135. }
  1136. })();
  1137. });
  1138. },
  1139. // 检查阿里巴巴登录状态
  1140. checkAlibabaLogin(){
  1141. this.checkLoading = true;
  1142. this.alibabaStatus = 1;
  1143. return new Promise((resolve, reject) => {
  1144. (async () => {
  1145. try{
  1146. if(this.loginBrowser){
  1147. await this.loginBrowser.close();
  1148. this.loginBrowser = null;
  1149. }
  1150. this.loginBrowser = await puppeteer.launch({
  1151. executablePath: this.initPath(),
  1152. args: ['--window-size=1280,800'],
  1153. userDataDir: this.initDataDir()
  1154. });
  1155. const page = await this.loginBrowser.newPage();
  1156. await page.setViewport({ width: 1280, height: 800 });
  1157. let testUrl = 'https://www.1688.com';
  1158. await page.goto(testUrl, {waitUntil : 'networkidle2'});
  1159. const cookies = await page.cookies();
  1160. let loginDiv = await page.$('div[class^=userNotLogin-]');
  1161. const loginEle = await page.$('div[class^=loginAvatar-]');
  1162. let loginText = '';
  1163. if (loginEle) {
  1164. loginText = await page.evaluate(el => el.innerText, loginEle);
  1165. }
  1166. const loginCookie = cookies.find(cookie =>
  1167. cookie.name === '__cn_logon__'
  1168. );
  1169. let logonValue = '';
  1170. if(loginCookie){
  1171. logonValue = loginCookie.value;
  1172. }
  1173. if(loginDiv || loginText == '登录' || logonValue == 'false' || logonValue == false){
  1174. this.alibabaStatus = 3; //未登录
  1175. }else{
  1176. this.alibabaStatus = 2;
  1177. }
  1178. resolve(this.alibabaStatus);
  1179. this.checkLoading = false;
  1180. await this.loginBrowser.close();
  1181. this.loginBrowser = null;
  1182. }catch(e){
  1183. this.checkLoading = false;
  1184. reject(3);
  1185. this.showError(e);
  1186. }
  1187. })();
  1188. });
  1189. },
  1190. // 1 - 阿里巴巴下载
  1191. async alibabaDownload(urlInfo, browser){
  1192. let task = await new Promise((resolve,reject) =>{
  1193. (async () => {
  1194. try{
  1195. let authority = this.$refs.headerRef.authority.isAuthority;
  1196. urlInfo.status = '2';
  1197. urlInfo.num = 0;
  1198. const page = await browser.newPage();
  1199. let waitUntil = 'networkidle2';
  1200. waitUntil = this.initDevelop().waitUntil;
  1201. let goUrl = urlInfo.url;
  1202. if(this.menuIndex == '1' && goUrl.indexOf('version=0') == -1){ // 阿里巴巴
  1203. if(goUrl.indexOf('?') > -1){
  1204. goUrl += "&version=0";
  1205. }else{
  1206. goUrl += "?verison=0";
  1207. }
  1208. }
  1209. await page.goto(goUrl, {waitUntil : waitUntil});
  1210. if(urlInfo.title){
  1211. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  1212. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1213. } else {
  1214. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  1215. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1216. }
  1217. }else{
  1218. await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
  1219. }
  1220. let pageInfo = await page.evaluate(() => {
  1221. let cHeight = document.documentElement.clientHeight;
  1222. let scrollHeight = document.body.scrollHeight;
  1223. return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
  1224. });
  1225. let scrollHeight = pageInfo.scrollHeight;
  1226. let cHeight = pageInfo.cHeight;
  1227. let num = Math.ceil(scrollHeight / cHeight);
  1228. let start = -1;
  1229. let scrollTime = this.initMs();
  1230. if(scrollTime < 800 && this.menuIndex == '6'){
  1231. scrollTime = 800;
  1232. }
  1233. let scrollInt = setInterval(async() => {
  1234. start ++;
  1235. if(this.settingArr.indexOf('detailImg') > -1){
  1236. let scrollHeight2 = await page.evaluate((start) => {
  1237. let scrollHeight = document.body.scrollHeight;
  1238. let cHeight = document.documentElement.clientHeight;
  1239. // let num = Math.ceil(scrollHeight / cHeight);
  1240. window.scrollTo({
  1241. top: cHeight * start,
  1242. behavior: "smooth"
  1243. });
  1244. return scrollHeight;
  1245. }, start);
  1246. num = Math.ceil(scrollHeight2 / cHeight);
  1247. }
  1248. if(start > num || start > 200){ // 防止页面过长,滚动200次自动停止
  1249. urlInfo.status = '3';
  1250. clearInterval(scrollInt);
  1251. if(this.menuIndex == '1'){ // 阿里巴巴
  1252. await this.alibabaScanImg(browser, page, urlInfo, authority);
  1253. }else if(this.menuIndex == '6'){ //阿里国际
  1254. await this.aliguojiScanImg(browser, page, urlInfo, authority);
  1255. }else if(this.menuIndex == '7'){ // 爱采购
  1256. await this.acaigouScanImg(browser, page, urlInfo, authority);
  1257. }else if(this.menuIndex == '8'){ // 亚马逊
  1258. await this.amazonScanImg(browser, page, urlInfo, authority);
  1259. }
  1260. this.loading = false;
  1261. urlInfo.status = '4';
  1262. resolve(true);
  1263. }
  1264. }, scrollTime);
  1265. }catch(e){
  1266. urlInfo.status = '5';
  1267. reject(e);
  1268. this.showError(e);
  1269. }
  1270. })();
  1271. });
  1272. },
  1273. // 检查京东登录状态
  1274. checkJdLogin(){
  1275. this.checkLoading = true;
  1276. this.jdStatus = 1;
  1277. return new Promise((resolve, reject) => {
  1278. (async () => {
  1279. try{
  1280. if(this.loginBrowser){
  1281. await this.loginBrowser.close();
  1282. this.loginBrowser = null;
  1283. }
  1284. this.loginBrowser = await puppeteer.launch({
  1285. executablePath: this.initPath(),
  1286. userDataDir: this.initDataDir('jd'),
  1287. args: [
  1288. '--start-maximized',
  1289. '--no-sandbox',
  1290. '--disable-setuid-sandbox',
  1291. '--disable-blink-features=AutomationControlled',
  1292. '--window-size=1280,800'
  1293. ]
  1294. });
  1295. const page = await this.loginBrowser.newPage();
  1296. await page.setViewport({ width: 1280, height: 800 });
  1297. let testUrl = 'https://www.jd.com';
  1298. await page.goto(testUrl, {waitUntil : 'networkidle2'});
  1299. let loginInfo = await page.evaluate(() => {
  1300. let navTags = document.querySelector('.link-login');
  1301. let userTags = document.querySelector('.nickname');
  1302. let userTags2 = document.querySelector('.nick'); //企业账号
  1303. let userInfo2 = document.querySelector('.login_info'); //页面右侧的登录信息
  1304. let userTags3 = false;
  1305. if(userInfo2 && userInfo2.innerText.indexOf('退出') > -1){
  1306. userTags3 = true;
  1307. }
  1308. if(navTags && navTags.innerHTML.indexOf('请登录') > -1 && !userTags3){
  1309. return false;
  1310. }else if(userTags || userTags2 || userTags3){
  1311. return true;
  1312. }else{
  1313. return false;
  1314. }
  1315. });
  1316. if(loginInfo){
  1317. this.jdStatus = 2;
  1318. }else{
  1319. this.jdStatus = 3;
  1320. }
  1321. resolve(this.jdStatus);
  1322. this.checkLoading = false;
  1323. await this.loginBrowser.close();
  1324. this.loginBrowser = null;
  1325. }catch(e){
  1326. this.checkLoading = false;
  1327. reject(3);
  1328. this.showError(e);
  1329. }
  1330. })();
  1331. });
  1332. },
  1333. // 京东下载
  1334. async jdScanImg(urlInfo, jdBrowser){
  1335. let task = await new Promise((resolve,reject) =>{
  1336. (async () => {
  1337. try{
  1338. let authority = this.$refs.headerRef.authority.isAuthority;
  1339. urlInfo.status = '2';
  1340. urlInfo.num = 0;
  1341. const page = await jdBrowser.newPage();
  1342. await page.evaluateOnNewDocument(() => {
  1343. const newProto = navigator.__proto__;
  1344. delete newProto.webdriver;
  1345. navigator.__proto__ = newProto;
  1346. window.navigator.chrome = {
  1347. runtime: {}
  1348. };
  1349. });
  1350. let jdImgInfo = {
  1351. mainImg: [],
  1352. skuImg: [],
  1353. commentImg: [],
  1354. detailImg: [],
  1355. video: []
  1356. };
  1357. let titleFlag = true;
  1358. let skuNum = 0, mainNum = 0, videoNum = 0;
  1359. page.on('response', async(response) => {
  1360. if(titleFlag){ // 第一次生成页面标题
  1361. if(urlInfo.title){
  1362. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  1363. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1364. } else {
  1365. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  1366. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1367. }
  1368. }else{
  1369. await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
  1370. }
  1371. titleFlag = false;
  1372. }
  1373. // 检查响应的 MIME 类型是否以 'image/' 开头
  1374. if (response.headers()['content-type']) {
  1375. let detailUrl = '';
  1376. let videoUrl = '';
  1377. if(response.url().indexOf('/description/') > -1){ // 商品详情接口
  1378. detailUrl = response.url();
  1379. }
  1380. if(response.url().indexOf('/tencent/video_v3') > -1){ // 商品视频接口
  1381. videoUrl = response.url();
  1382. }
  1383. urlInfo.status = '3';
  1384. if(detailUrl && this.settingArr.indexOf('detailImg') > -1){ // jd商品详情
  1385. try {
  1386. let data = await response.text();
  1387. if(data.indexOf('showdesc(') > -1){
  1388. data = data.slice(0, -1).replace('showdesc(', '');
  1389. }
  1390. let detailInfo = JSON.parse(data);
  1391. let regex = /\/\/img[0-9]+.360buyimg.com\S+.(jpg|jpeg|png|gif|avif|tif|tiff)/g;
  1392. let detailImgArr = [];
  1393. if(detailInfo && detailInfo.content){
  1394. if(detailInfo.content.match(regex)){
  1395. detailImgArr = detailInfo.content.match(regex);
  1396. }
  1397. }
  1398. jdImgInfo.detailImg = detailImgArr;
  1399. for(let i = 0; i < detailImgArr.length; i++){
  1400. let imgUrl = 'https:' + detailImgArr[i];
  1401. imgUrl = imgUrl.replace('.avif', '');
  1402. let fileName = imgUrl.split('/').pop();
  1403. if(fileName){
  1404. let queryIndex = fileName.indexOf('?');
  1405. if (queryIndex !== -1) {
  1406. fileName = fileName.substr(0, queryIndex);
  1407. }
  1408. let num = Number(i) + 1;
  1409. let suffix = '';
  1410. if(fileName.lastIndexOf('.') > -1){
  1411. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1412. }
  1413. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  1414. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  1415. }
  1416. let outputPath = urlInfo.newPath + '\\详情图\\详情图' + num + suffix;
  1417. if(!authority && i < this.execNum){
  1418. await this.downloadImage(imgUrl, outputPath, urlInfo);
  1419. }
  1420. if(authority){
  1421. await this.downloadImage(imgUrl, outputPath, urlInfo);
  1422. }
  1423. }
  1424. }
  1425. } catch (error) {
  1426. console.error('详情图片解析失败:', error);
  1427. }
  1428. }
  1429. if(videoUrl && this.settingArr.indexOf('video') > -1){ // jd商品视频
  1430. try {
  1431. let data = await response.text();
  1432. data = data.slice(0, -1).replace(/^jQuery[0-9]+\(/, '');
  1433. let videoInfo = JSON.parse(data);
  1434. let videoUrl = videoInfo.playUrl;
  1435. jdImgInfo.video.push(videoUrl);
  1436. let fileName = videoUrl.split('/').pop();
  1437. if(fileName){
  1438. let queryIndex = fileName.indexOf('?');
  1439. if (queryIndex !== -1) {
  1440. fileName = fileName.substr(0, queryIndex);
  1441. }
  1442. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  1443. fs.mkdirSync(urlInfo.newPath + '\\视频');
  1444. }
  1445. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  1446. await this.downloadImage(videoUrl, outputPath, urlInfo);
  1447. }
  1448. } catch (error) {
  1449. console.error('视频解析失败:', error);
  1450. }
  1451. }
  1452. }
  1453. });
  1454. await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
  1455. let pageInfo = await page.evaluate(() => {
  1456. let cHeight = document.documentElement.clientHeight;
  1457. let scrollHeight = document.body.scrollHeight;
  1458. return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
  1459. });
  1460. let scrollHeight = pageInfo.scrollHeight;
  1461. let cHeight = pageInfo.cHeight;
  1462. let num = Math.ceil(scrollHeight / cHeight);
  1463. let start = -1;
  1464. let scrollTime = this.initMs();
  1465. let scrollInt = setInterval(async() => {
  1466. start ++;
  1467. if(this.settingArr.indexOf('detailImg') > -1){ // 选择详情图
  1468. let scrollHeight2 = await page.evaluate((start) => {
  1469. let scrollHeight = document.body.scrollHeight;
  1470. let cHeight = document.documentElement.clientHeight;
  1471. let obj = document.querySelector('.detail-content') || document.querySelector('.detail-content-item');
  1472. if(obj && obj.getBoundingClientRect().top < 0){
  1473. return -1;
  1474. }
  1475. window.scrollTo({
  1476. top: cHeight * start,
  1477. behavior: "smooth"
  1478. });
  1479. return scrollHeight;
  1480. }, start);
  1481. if(scrollHeight2 > 0){
  1482. num = Math.ceil(scrollHeight2 / cHeight);
  1483. }else{
  1484. num = 0;
  1485. }
  1486. }else{
  1487. num = 0;
  1488. }
  1489. if(start > num || start > 20){ // 防止页面过长,滚动20次自动停止
  1490. clearInterval(scrollInt);
  1491. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  1492. const imgInfo = await page.evaluate((authority, execNum) => {
  1493. let outObj = {
  1494. mainImg: [],
  1495. skuImg: [],
  1496. detailImg: []
  1497. };
  1498. //主图
  1499. let arr1 = document.querySelectorAll('#spec-list img');
  1500. for(let i=0; i< arr1.length; i++){
  1501. let mainImgUrl = arr1[i].src;
  1502. let reg = /\/n[0-9]+\/jfs\//;
  1503. let reg2 = /\/n[0-9]+\/s([0-9]+)x([0-9]+)_jfs\//;
  1504. let reg3 = /![a-z]+_[0-9]+x[0-9]+(.avif)?/;
  1505. let replaceStr = '/n5/s800x800_jfs/';
  1506. if(mainImgUrl.match(/\/n[0-9]+\/s50x66_jfs\//)){
  1507. replaceStr = '/n5/s750x1000_jfs/';
  1508. }
  1509. mainImgUrl = mainImgUrl.replace(reg, replaceStr).replace(reg2, replaceStr).replace(reg3, '').replace('.avif', '');
  1510. if(!authority && i < execNum){
  1511. outObj.mainImg.push(mainImgUrl);
  1512. }
  1513. if(authority){
  1514. outObj.mainImg.push(mainImgUrl);
  1515. }
  1516. }
  1517. //sku图片
  1518. let arr2 = document.querySelectorAll('#choose-attr-1 img');
  1519. for(let i=0; i< arr2.length; i++){
  1520. let skuImgUrl = arr2[i].src;
  1521. let skuReg = /\/n[0-9]+\/s([0-9]+)x([0-9]+)_jfs\//;
  1522. let replaceStr = '/n5/s800x800_jfs/';
  1523. if(skuImgUrl.match(/\/n[0-9]+\/s60x80_jfs\//)){
  1524. replaceStr = '/n5/s750x1000_jfs/';
  1525. }
  1526. skuImgUrl = skuImgUrl.replace(skuReg, replaceStr).replace('.avif', '');
  1527. if(!authority && i < execNum){
  1528. outObj.skuImg.push(skuImgUrl);
  1529. }
  1530. if(authority){
  1531. outObj.skuImg.push(skuImgUrl);
  1532. }
  1533. }
  1534. //详情图 - 图片类目需要网页直接抓取
  1535. let arr3 = document.querySelectorAll('.book-detail-content img');
  1536. for(let i=0; i< arr3.length; i++){
  1537. let detailImgUrl = arr3[i].src;
  1538. detailImgUrl = detailImgUrl.replace('.avif', '');
  1539. if(!authority && i < execNum){
  1540. outObj.detailImg.push(detailImgUrl);
  1541. }
  1542. if(authority){
  1543. outObj.detailImg.push(detailImgUrl);
  1544. }
  1545. }
  1546. return outObj;
  1547. }, authority, this.execNum);
  1548. if(this.settingArr.indexOf('mainImg') > -1){
  1549. // 主图下载
  1550. for(let j = 0; j < imgInfo.mainImg.length; j++){
  1551. let fileName = imgInfo.mainImg[j].split('/').pop();
  1552. if(fileName){
  1553. let queryIndex = fileName.indexOf('?');
  1554. if (queryIndex !== -1) {
  1555. fileName = fileName.substr(0, queryIndex);
  1556. }
  1557. let num = Number(j) + 1;
  1558. let suffix = '';
  1559. if(fileName.lastIndexOf('.') > -1){
  1560. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1561. }
  1562. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  1563. fs.mkdirSync(urlInfo.newPath + '\\主图');
  1564. }
  1565. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  1566. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  1567. }
  1568. }
  1569. }
  1570. // sku图片下载
  1571. if(this.settingArr.indexOf('skuImg') > -1){
  1572. for(let j = 0; j < imgInfo.skuImg.length; j++){
  1573. let fileName = imgInfo.skuImg[j].split('/').pop();
  1574. if(fileName){
  1575. let queryIndex = fileName.indexOf('?');
  1576. if (queryIndex !== -1) {
  1577. fileName = fileName.substr(0, queryIndex);
  1578. }
  1579. let num = Number(j) + 1;
  1580. let suffix = '';
  1581. if(fileName.lastIndexOf('.') > -1){
  1582. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1583. }
  1584. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  1585. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  1586. }
  1587. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  1588. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  1589. }
  1590. }
  1591. }
  1592. // 详情图下载 --图书类目
  1593. if(this.settingArr.indexOf('detailImg') > -1 && jdImgInfo.detailImg.length == 0){
  1594. for(let j = 0; j < imgInfo.detailImg.length; j++){
  1595. let fileName = imgInfo.detailImg[j].split('/').pop();
  1596. if(fileName){
  1597. let queryIndex = fileName.indexOf('?');
  1598. if (queryIndex !== -1) {
  1599. fileName = fileName.substr(0, queryIndex);
  1600. }
  1601. let num = Number(j) + 1;
  1602. let suffix = '';
  1603. if(fileName.lastIndexOf('.') > -1){
  1604. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1605. }
  1606. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  1607. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  1608. }
  1609. let outputPath = urlInfo.newPath + '\\详情图\\详情图' + num + suffix;
  1610. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  1611. }
  1612. }
  1613. }
  1614. /**end**/
  1615. await page.close();
  1616. urlInfo.status = '4';
  1617. resolve(true);
  1618. this.loading = false;
  1619. }
  1620. }, scrollTime);
  1621. }catch(e){
  1622. reject(e);
  1623. this.showError(e);
  1624. }
  1625. })();
  1626. });
  1627. },
  1628. // 检查天猫淘宝登录状态
  1629. checkLogin(){
  1630. this.checkLoading = true;
  1631. this.tbStatus = 1;
  1632. return new Promise((resolve, reject) => {
  1633. (async () => {
  1634. try{
  1635. if(this.loginBrowser){
  1636. await this.loginBrowser.close();
  1637. this.loginBrowser = null;
  1638. }
  1639. this.loginBrowser = await puppeteer.launch({
  1640. executablePath: this.initPath(),
  1641. args: ['--window-size=1280,800'],
  1642. userDataDir: this.initDataDir()
  1643. });
  1644. const page = await this.loginBrowser.newPage();
  1645. await page.setViewport({ width: 1280, height: 800 });
  1646. let testUrl = 'https://www.taobao.com';
  1647. await page.goto(testUrl, {waitUntil : 'networkidle2'});
  1648. let loginInfo = await page.evaluate(() => {
  1649. let navTags = document.querySelector('.site-nav-sign a');
  1650. let userTags = document.querySelector('.site-nav-user a');
  1651. if(navTags && navTags.innerHTML.indexOf('登录') > -1){
  1652. return false;
  1653. }else if(userTags){
  1654. return true;
  1655. }else{
  1656. return false;
  1657. }
  1658. });
  1659. if(loginInfo){
  1660. this.tbStatus = 2;
  1661. }else{
  1662. this.tbStatus = 3;
  1663. }
  1664. resolve(this.tbStatus);
  1665. this.checkLoading = false;
  1666. await this.loginBrowser.close();
  1667. this.loginBrowser = null;
  1668. }catch(e){
  1669. this.checkLoading = false;
  1670. reject(3);
  1671. this.showError(e);
  1672. }
  1673. })();
  1674. });
  1675. },
  1676. // 淘宝天猫扫描下载图片
  1677. async tbScanImg(urlInfo, tbBrowser){
  1678. let task = await new Promise((resolve,reject) =>{
  1679. (async () => {
  1680. try{
  1681. let authority = this.$refs.headerRef.authority.isAuthority;
  1682. urlInfo.status = '2';
  1683. urlInfo.num = 0;
  1684. let page = await tbBrowser.newPage();
  1685. let responseVideo = [];
  1686. page.on('response', async(response) => {
  1687. // 检查响应的 MIME 类型是否以 'video/' 开头
  1688. if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('video/')) {
  1689. if(responseVideo.indexOf(response.url()) < 0 && !response.url().startsWith('blob:https://')){
  1690. responseVideo.push(response.url());
  1691. }
  1692. }
  1693. });
  1694. let waitUntil = 'networkidle2';
  1695. waitUntil = this.initDevelop().waitUntil;
  1696. await page.goto(urlInfo.url, {waitUntil : waitUntil});
  1697. if(this.settingArr.indexOf('video') > -1){ // 用户选择下载视频的时候才会触发
  1698. //鼠标放在主图第一张,生成视频
  1699. const elementHandle = await page.$('li[class*=thumbnail--]');
  1700. if(elementHandle){
  1701. const classListProperty = await elementHandle.getProperty('classList');
  1702. const classList = await classListProperty.jsonValue();
  1703. const classesArray = Object.values(classList);
  1704. const allClasses = classesArray.join('.');
  1705. if(allClasses && allClasses.indexOf('active-') < 0){
  1706. await page.hover('li.'+allClasses);
  1707. }
  1708. }
  1709. }
  1710. let frames = await page.$$('iframe');
  1711. if(frames.length == 1){ // 就一个
  1712. let isAdVisible = false;
  1713. try{ //判断是否是隐藏弹窗iframe
  1714. isAdVisible = await page.$eval('iframe', ad => {
  1715. return getComputedStyle(ad).display !== 'none';
  1716. });
  1717. }catch(e){
  1718. }
  1719. if(isAdVisible){
  1720. let m2 = await page.$('img[class*=thumbnailPic--]');
  1721. if(!m2){ // 出现弹窗而且没有主图,判断为拦截模式
  1722. await page.close();
  1723. urlInfo.status = '6';
  1724. resolve(true);
  1725. this.loading = false;
  1726. return false;
  1727. }
  1728. }
  1729. }else if(frames.length > 1){ //多个弹窗就判断是否有图片显示
  1730. let m2 = await page.$('img[class*=thumbnailPic--]');
  1731. if(!m2){ // 出现弹窗而且没有主图,判断为拦截模式
  1732. await page.close();
  1733. urlInfo.status = '6';
  1734. resolve(true);
  1735. this.loading = false;
  1736. return false;
  1737. }
  1738. }
  1739. let pageInfo = await page.evaluate(() => {
  1740. let cHeight = document.documentElement.clientHeight;
  1741. let scrollHeight = document.body.scrollHeight;
  1742. return {'scrollHeight': scrollHeight, 'cHeight': cHeight}
  1743. });
  1744. let scrollHeight = pageInfo.scrollHeight;
  1745. let cHeight = pageInfo.cHeight;
  1746. let num = Math.ceil(scrollHeight / cHeight);
  1747. let start = -1;
  1748. let scrollTime = this.initMs();
  1749. let scrollInt = setInterval(async() => {
  1750. start ++;
  1751. if(this.settingArr.indexOf('commentImg') > -1 && this.settingArr.indexOf('detailImg') < 0){ // 选择了评论图没选择详情图
  1752. let scrollHeight2 = await page.evaluate((start) => {
  1753. let scrollHeight = document.body.scrollHeight;
  1754. let cHeight = document.documentElement.clientHeight;
  1755. let obj = document.getElementById('container') || document.getElementById('content');
  1756. if(obj && obj.getBoundingClientRect().top < -500){
  1757. return -1;
  1758. }
  1759. window.scrollTo({
  1760. top: cHeight * start,
  1761. behavior: "smooth"
  1762. });
  1763. return scrollHeight;
  1764. }, start);
  1765. if(scrollHeight2 > 0){
  1766. num = Math.ceil(scrollHeight2 / cHeight);
  1767. }else{
  1768. num = 0;
  1769. }
  1770. }
  1771. if(this.settingArr.indexOf('detailImg') > -1){ // 选择详情图
  1772. let scrollHeight2 = await page.evaluate((start) => {
  1773. let scrollHeight = document.body.scrollHeight;
  1774. let cHeight = document.documentElement.clientHeight;
  1775. let obj = document.getElementById('container') || document.getElementById('content');
  1776. if(obj && obj.getBoundingClientRect().bottom < 100){
  1777. return -1;
  1778. }
  1779. window.scrollTo({
  1780. top: cHeight * start,
  1781. behavior: "smooth"
  1782. });
  1783. return scrollHeight;
  1784. }, start);
  1785. if(scrollHeight2 > 0){
  1786. num = Math.ceil(scrollHeight2 / cHeight);
  1787. }else{
  1788. num = 0;
  1789. }
  1790. }
  1791. if(this.settingArr.indexOf('skuImg') > -1 && this.settingArr.indexOf('commentImg') < 0 && this.settingArr.indexOf('detailImg') < 0){ // 选择了sku图片没选择评论和详情
  1792. let scrollHeight2 = await page.evaluate((start) => {
  1793. let scrollHeight = document.body.scrollHeight;
  1794. let cHeight = document.documentElement.clientHeight;
  1795. let obj = document.querySelector('div[class^=SkuContent--]');
  1796. if(obj && obj.getBoundingClientRect().bottom < 500){
  1797. return -1;
  1798. }
  1799. window.scrollTo({
  1800. top: cHeight * start,
  1801. behavior: "smooth"
  1802. });
  1803. return scrollHeight;
  1804. }, start);
  1805. if(scrollHeight2 > 0){
  1806. num = Math.ceil(scrollHeight2 / cHeight);
  1807. }else{
  1808. num = 0;
  1809. }
  1810. }
  1811. if(this.settingArr.indexOf('skuImg') < 0 && this.settingArr.indexOf('detailImg') < 0 && this.settingArr.indexOf('commentImg') < 0){ // 没有选择评论图和详情图
  1812. num = 0;
  1813. }
  1814. if(start > num || start > 200){ // 防止页面过长,滚动200次自动停止
  1815. urlInfo.status = '3';
  1816. clearInterval(scrollInt);
  1817. if(urlInfo.title){
  1818. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  1819. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1820. } else {
  1821. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  1822. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  1823. }
  1824. }else{
  1825. await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
  1826. }
  1827. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  1828. const imgInfo = await page.evaluate((authority, execNum) => {
  1829. let outObj = {
  1830. mainImg: [],
  1831. detailImg: [],
  1832. skuImg: [],
  1833. commentImg: [],
  1834. video: []
  1835. };
  1836. // 正则表达式匹配字符 重写图片路径
  1837. let regex = /\.(.{3,4})_[0-9a-zA-z]+\.(.{3,4})_\.(.{3,4})/;
  1838. //主图
  1839. let arr1 = document.querySelectorAll('img[class^=PicGallery--thumbnailPic--]');
  1840. if(arr1.length === 0){
  1841. arr1 = document.querySelectorAll('img[class*=thumbnailPic--]');
  1842. }
  1843. for(let i=0; i< arr1.length; i++){
  1844. let mainImgUrl = arr1[i].src;
  1845. let result = regex.exec(mainImgUrl);
  1846. if(result){
  1847. mainImgUrl = mainImgUrl.replace(result[0], '.'+result[1]);
  1848. }
  1849. if(!authority && i < execNum){
  1850. outObj.mainImg.push(mainImgUrl);
  1851. }
  1852. if(authority){
  1853. outObj.mainImg.push(mainImgUrl);
  1854. }
  1855. }
  1856. //sku图片
  1857. let arr2 = document.querySelectorAll('img[class^=SkuContent--valueItemImg--]');
  1858. if(arr2.length === 0){
  1859. arr2 = document.querySelectorAll('img[class*=valueItemImg--]');
  1860. }
  1861. for(let i=0; i< arr2.length; i++){
  1862. let skuImgUrl = arr2[i].src;
  1863. let result = regex.exec(skuImgUrl);
  1864. if(result){
  1865. skuImgUrl = skuImgUrl.replace(result[0], '.'+result[1]);
  1866. }
  1867. if(!authority && i < execNum){
  1868. outObj.skuImg.push(skuImgUrl);
  1869. }
  1870. if(authority){
  1871. outObj.skuImg.push(skuImgUrl);
  1872. }
  1873. }
  1874. //详情图片
  1875. let arr3 = document.querySelectorAll('#content img');
  1876. for(let i=0; i< arr3.length; i++){
  1877. let detailImgUrl = arr3[i].src;
  1878. let lazyUrl = arr3[i].getAttribute('data-src');
  1879. if(arr3[i].src.indexOf('/s.gif') > -1 && lazyUrl){
  1880. detailImgUrl = lazyUrl;
  1881. if(!/^http/.exec(lazyUrl)){
  1882. detailImgUrl = 'https:' + lazyUrl;
  1883. }
  1884. }
  1885. let result = regex.exec(detailImgUrl);
  1886. if(result){
  1887. detailImgUrl = detailImgUrl.replace(result[0], '.'+result[1]);
  1888. }
  1889. if(!authority && i < execNum){
  1890. outObj.detailImg.push(detailImgUrl);
  1891. }
  1892. if(authority){
  1893. outObj.detailImg.push(detailImgUrl);
  1894. }
  1895. }
  1896. //评论图片
  1897. let arr4 = document.querySelectorAll('div[class*=Comments--] img');
  1898. if(arr4.length === 0){
  1899. arr4 = document.querySelectorAll('div[class*=comments--] img');
  1900. }
  1901. for(let i=0; i< arr4.length; i++){
  1902. if(arr4[i].src.indexOf('/avatar/sns/user/flag/sns_logo') == -1 && arr4[i].className.indexOf('creditImg') == -1){ //过滤淘宝用户头像
  1903. if(!authority && i < execNum){
  1904. outObj.commentImg.push(arr4[i].src);
  1905. }
  1906. if(authority){
  1907. outObj.commentImg.push(arr4[i].src);
  1908. }
  1909. }
  1910. }
  1911. // 视频
  1912. let arr5 = document.querySelectorAll('video');
  1913. for(let i=0; i< arr5.length; i++){
  1914. if(outObj.video.indexOf(arr5[i].src) == -1){
  1915. if(!authority && i < execNum){
  1916. outObj.video.push(arr5[i].src);
  1917. }
  1918. if(authority){
  1919. outObj.video.push(arr5[i].src);
  1920. }
  1921. }
  1922. }
  1923. return outObj;
  1924. }, authority, this.execNum);
  1925. if(responseVideo.length > 0){
  1926. for(let l=0; l<responseVideo.length; l++){
  1927. if(imgInfo.video.indexOf(responseVideo[l]) == -1){
  1928. imgInfo.video.push(responseVideo[l]);
  1929. }
  1930. }
  1931. }
  1932. if(this.settingArr.indexOf('mainImg') > -1){
  1933. // 主图下载
  1934. for(let j = 0; j < imgInfo.mainImg.length; j++){
  1935. let fileName = imgInfo.mainImg[j].split('/').pop();
  1936. if(fileName){
  1937. let queryIndex = fileName.indexOf('?');
  1938. if (queryIndex !== -1) {
  1939. fileName = fileName.substr(0, queryIndex);
  1940. }
  1941. let num = Number(j) + 1;
  1942. let suffix = '';
  1943. if(fileName.lastIndexOf('.') > -1){
  1944. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1945. }
  1946. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  1947. fs.mkdirSync(urlInfo.newPath + '\\主图');
  1948. }
  1949. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  1950. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  1951. }
  1952. }
  1953. }
  1954. // sku图片下载
  1955. if(this.settingArr.indexOf('skuImg') > -1){
  1956. for(let j = 0; j < imgInfo.skuImg.length; j++){
  1957. let fileName = imgInfo.skuImg[j].split('/').pop();
  1958. if(fileName){
  1959. let queryIndex = fileName.indexOf('?');
  1960. if (queryIndex !== -1) {
  1961. fileName = fileName.substr(0, queryIndex);
  1962. }
  1963. let num = Number(j) + 1;
  1964. let suffix = '';
  1965. if(fileName.lastIndexOf('.') > -1){
  1966. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1967. }
  1968. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  1969. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  1970. }
  1971. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  1972. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  1973. }
  1974. }
  1975. }
  1976. //详情图下载
  1977. if(this.settingArr.indexOf('detailImg') > -1){
  1978. for(let j = 0; j < imgInfo.detailImg.length; j++){
  1979. let fileName = imgInfo.detailImg[j].split('/').pop();
  1980. if(fileName){
  1981. let queryIndex = fileName.indexOf('?');
  1982. if (queryIndex !== -1) {
  1983. fileName = fileName.substr(0, queryIndex);
  1984. }
  1985. let num = Number(j) + 1;
  1986. let suffix = '';
  1987. if(fileName.lastIndexOf('.') > -1){
  1988. suffix = fileName.substr(fileName.lastIndexOf('.'));
  1989. }
  1990. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  1991. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  1992. }
  1993. let outputPath = urlInfo.newPath + '\\详情图\\详情图' + num + suffix;
  1994. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  1995. }
  1996. }
  1997. }
  1998. //评论图下载
  1999. if(this.settingArr.indexOf('commentImg') > -1){
  2000. for(let j = 0; j < imgInfo.commentImg.length; j++){
  2001. let fileName = imgInfo.commentImg[j].split('/').pop();
  2002. if(fileName){
  2003. let queryIndex = fileName.indexOf('?');
  2004. if (queryIndex !== -1) {
  2005. fileName = fileName.substr(0, queryIndex);
  2006. }
  2007. let num = Number(j) + 1;
  2008. let suffix = '';
  2009. if(fileName.lastIndexOf('.') > -1){
  2010. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2011. }
  2012. if (!fs.existsSync(urlInfo.newPath + '\\评论图')) {
  2013. fs.mkdirSync(urlInfo.newPath + '\\评论图');
  2014. }
  2015. let outputPath = urlInfo.newPath + '\\评论图\\评论图' + num + suffix;
  2016. await this.downloadImage(imgInfo.commentImg[j], outputPath, urlInfo);
  2017. }
  2018. }
  2019. }
  2020. //视频下载
  2021. if(this.settingArr.indexOf('video') > -1){
  2022. for(let j = 0; j < imgInfo.video.length; j++){
  2023. let fileName = imgInfo.video[j].split('/').pop();
  2024. if(fileName){
  2025. let queryIndex = fileName.indexOf('?');
  2026. if (queryIndex !== -1) {
  2027. fileName = fileName.substr(0, queryIndex);
  2028. }
  2029. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  2030. fs.mkdirSync(urlInfo.newPath + '\\视频');
  2031. }
  2032. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  2033. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2034. }
  2035. }
  2036. }
  2037. await page.close();
  2038. urlInfo.status = '4';
  2039. resolve(true);
  2040. this.loading = false;
  2041. }
  2042. }, scrollTime);
  2043. }catch(e){
  2044. reject(e);
  2045. this.showError(e);
  2046. }
  2047. })();
  2048. });
  2049. },
  2050. // 阿里巴巴 - 扫描并下载图片
  2051. async alibabaScanImg(browser, page, urlInfo, authority){
  2052. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2053. const imgInfo = await page.evaluate((authority, execNum) => {
  2054. let outObj = {
  2055. mainImg: [],
  2056. detailImg: [],
  2057. skuImg: [],
  2058. commentImg: [],
  2059. video: []
  2060. };
  2061. //主图
  2062. let arr1 = document.querySelectorAll('img[class*="-gallery-img"]');
  2063. for(let i=0; i< arr1.length; i++){
  2064. let srcUrl = arr1[i].src;
  2065. if(srcUrl.endsWith('_b.jpg')){
  2066. srcUrl = srcUrl.replace(/_b\.jpg$/, '');
  2067. }
  2068. if(!authority && i < execNum){
  2069. outObj.mainImg.push(srcUrl);
  2070. }
  2071. if(authority){
  2072. outObj.mainImg.push(srcUrl);
  2073. }
  2074. }
  2075. //sku图片
  2076. let type = 'bg';
  2077. let arr2 = document.querySelectorAll('.prop-img');
  2078. if(arr2.length == 0){
  2079. arr2 = document.querySelectorAll('.sku-item-image');
  2080. }
  2081. if(arr2.length == 0){
  2082. arr2 = document.querySelectorAll('.ant-image-img');
  2083. type = 'img';
  2084. }
  2085. for(let i=0; i< arr2.length; i++){
  2086. let src;
  2087. if(type == 'bg'){
  2088. src = window.getComputedStyle(arr2[i]).backgroundImage.replace(/url\(["']?(.+?)["']?\)/i, '$1');
  2089. }
  2090. if(type == 'img'){
  2091. src = arr2[i].src;
  2092. }
  2093. if(src.endsWith('_sum.jpg')){
  2094. src = src.replace(/_sum\.jpg$/, '');
  2095. }
  2096. if(!authority && i < execNum){
  2097. outObj.skuImg.push(src);
  2098. }
  2099. if(authority){
  2100. outObj.skuImg.push(src);
  2101. }
  2102. }
  2103. //详情图片
  2104. let arr3 = document.querySelectorAll('img.desc-img-loaded');
  2105. if(arr3.length == 0){
  2106. if(document.getElementById('description') && document.getElementById('description').querySelector('.html-description')){
  2107. arr3 = document.getElementById('description').querySelector('.html-description').shadowRoot.querySelectorAll('img');
  2108. }
  2109. }
  2110. for(let i=0; i< arr3.length; i++){
  2111. if(!authority && i < execNum){
  2112. outObj.detailImg.push(arr3[i].src);
  2113. }
  2114. if(authority){
  2115. outObj.detailImg.push(arr3[i].src);
  2116. }
  2117. }
  2118. // 视频
  2119. let arr5 = document.querySelectorAll('video');
  2120. for(let i=0; i< arr5.length; i++){
  2121. if(outObj.video.indexOf(arr5[i].src) == -1){
  2122. if(!authority && i < execNum){
  2123. outObj.video.push(arr5[i].src);
  2124. }
  2125. if(authority){
  2126. outObj.video.push(arr5[i].src);
  2127. }
  2128. }
  2129. }
  2130. return outObj;
  2131. }, authority, this.execNum);
  2132. // 主图下载
  2133. if(this.settingArr.indexOf('mainImg') > -1){
  2134. for(let j = 0; j < imgInfo.mainImg.length; j++){
  2135. let fileName = imgInfo.mainImg[j].split('/').pop();
  2136. if(fileName){
  2137. let queryIndex = fileName.indexOf('?');
  2138. if (queryIndex !== -1) {
  2139. fileName = fileName.substr(0, queryIndex);
  2140. }
  2141. let num = Number(j) + 1;
  2142. let suffix = '';
  2143. if(fileName.lastIndexOf('.') > -1){
  2144. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2145. }
  2146. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  2147. fs.mkdirSync(urlInfo.newPath + '\\主图');
  2148. }
  2149. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  2150. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  2151. }
  2152. }
  2153. }
  2154. // sku图片下载
  2155. if(this.settingArr.indexOf('skuImg') > -1){
  2156. for(let j = 0; j < imgInfo.skuImg.length; j++){
  2157. let fileName = imgInfo.skuImg[j].split('/').pop();
  2158. if(fileName){
  2159. let queryIndex = fileName.indexOf('?');
  2160. if (queryIndex !== -1) {
  2161. fileName = fileName.substr(0, queryIndex);
  2162. }
  2163. let num = Number(j) + 1;
  2164. let suffix = '';
  2165. if(fileName.lastIndexOf('.') > -1){
  2166. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2167. }
  2168. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  2169. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  2170. }
  2171. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  2172. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  2173. }
  2174. }
  2175. }
  2176. //详情图下载
  2177. if(this.settingArr.indexOf('detailImg') > -1){
  2178. for(let j = 0; j < imgInfo.detailImg.length; j++){
  2179. let fileName = imgInfo.detailImg[j].split('/').pop();
  2180. if(fileName){
  2181. let queryIndex = fileName.indexOf('?');
  2182. if (queryIndex !== -1) {
  2183. fileName = fileName.substr(0, queryIndex);
  2184. }
  2185. let num = Number(j) + 1;
  2186. let suffix = '';
  2187. if(fileName.lastIndexOf('.') > -1){
  2188. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2189. }
  2190. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  2191. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  2192. }
  2193. let outputPath = urlInfo.newPath + '\\详情图\\' + '详情图' + num + suffix;
  2194. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  2195. }
  2196. }
  2197. }
  2198. //视频下载
  2199. if(this.settingArr.indexOf('video') > -1){
  2200. for(let j = 0; j < imgInfo.video.length; j++){
  2201. let fileName = imgInfo.video[j].split('/').pop();
  2202. if(fileName){
  2203. let queryIndex = fileName.indexOf('?');
  2204. if (queryIndex !== -1) {
  2205. fileName = fileName.substr(0, queryIndex);
  2206. }
  2207. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  2208. fs.mkdirSync(urlInfo.newPath + '\\视频');
  2209. }
  2210. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  2211. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2212. }
  2213. }
  2214. }
  2215. await page.close(); // 关闭页面但不关闭浏览器
  2216. },
  2217. // 检查小红书登录状态
  2218. checkRedLogin(){
  2219. this.checkLoading = true;
  2220. this.redStatus = 1;
  2221. return new Promise((resolve, reject) => {
  2222. (async () => {
  2223. try{
  2224. if(this.loginBrowser){
  2225. await this.loginBrowser.close();
  2226. this.loginBrowser = null;
  2227. }
  2228. puppeteer.use(StealthPlugin());
  2229. this.loginBrowser = await puppeteer.launch({
  2230. executablePath: this.initPath(),
  2231. userDataDir: this.initDataDir(),
  2232. args: [
  2233. '--start-maximized',
  2234. '--no-sandbox',
  2235. '--disable-setuid-sandbox',
  2236. '--disable-blink-features=AutomationControlled',
  2237. '--window-size=1280,800'
  2238. ],
  2239. });
  2240. const page = await this.loginBrowser.newPage();
  2241. await page.setViewport({ width: 1280, height: 800 });
  2242. let testUrl = "https://www.xiaohongshu.com";
  2243. await page.goto(testUrl, {waitUntil : 'networkidle2'});
  2244. let loginBtn = await page.$$('#login-btn');
  2245. let loginContainer = await page.$$('.login-container');
  2246. if(loginContainer.length > 0 || loginBtn.length > 0){
  2247. this.redStatus = 3; //未登录
  2248. }else{
  2249. this.redStatus = 2;
  2250. }
  2251. resolve(this.redStatus);
  2252. this.checkLoading = false;
  2253. await this.loginBrowser.close();
  2254. this.loginBrowser = null;
  2255. }catch(e){
  2256. this.checkLoading = false;
  2257. reject(3);
  2258. this.showError(e);
  2259. }
  2260. })();
  2261. });
  2262. },
  2263. // 5-小红书下载
  2264. async redDownload(urlInfo, redBrowser){
  2265. let task = await new Promise((resolve,reject) =>{
  2266. (async () => {
  2267. try{
  2268. let authority = this.$refs.headerRef.authority.isAuthority;
  2269. let number = 0;
  2270. urlInfo.status = '2';
  2271. urlInfo.num = 0;
  2272. const page = await redBrowser.newPage();
  2273. let responseVideo = [];
  2274. page.on('response', async(response) => {
  2275. // 检查响应的 MIME 类型是否以 'video/' 开头
  2276. if (response.headers()['content-type'] && response.headers()['content-type'].startsWith('video/')) {
  2277. if(responseVideo.indexOf(response.url()) < 0 && !response.url().startsWith('blob:https://')){
  2278. responseVideo.push(response.url());
  2279. }
  2280. }
  2281. });
  2282. await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
  2283. if(urlInfo.title){
  2284. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  2285. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  2286. } else {
  2287. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  2288. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  2289. }
  2290. }else{
  2291. await this.getTitle(page, urlInfo); // 生成页面标题对应的文件夹
  2292. }
  2293. urlInfo.status = '3';
  2294. // 定位元素
  2295. const handle = await page.$$('.pagination-media-container .pagination-item');
  2296. if(handle.length > 0 && this.settingArr.indexOf('video') > -1){ // 模拟鼠标拖动 将鼠标移动到元素的中心,然后开始拖动
  2297. let handleLength = handle.length;
  2298. const box = await handle[0].boundingBox();
  2299. const boxEnd = await handle[handleLength - 1].boundingBox();
  2300. if(box && boxEnd){ //确保元素可见,防止报错
  2301. const center = {
  2302. x: box.x + box.width / 2,
  2303. y: box.y + box.height / 2
  2304. };
  2305. const centerEnd = {
  2306. x: boxEnd.x + boxEnd.width / 2,
  2307. y: boxEnd.y + boxEnd.height / 2
  2308. };
  2309. await page.mouse.move(center.x, center.y);
  2310. await page.mouse.down();
  2311. await page.mouse.move(centerEnd.x, centerEnd.y, { steps: 50 }); // 新的位置,可以根据需要调整步骤数
  2312. }
  2313. }
  2314. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2315. const imgInfo = await page.evaluate((authority, execNum) => {
  2316. let outObj = {
  2317. mainImg: [],
  2318. detailImg: [],
  2319. skuImg: [],
  2320. commentImg: [],
  2321. video: []
  2322. };
  2323. // 正则表达式匹配字符 重写图片路径
  2324. let regex = /\.(.{3,4})_[0-9a-zA-z]+\.(.{3,4})_\.(.{3,4})/;
  2325. //主图
  2326. let arr1 = document.querySelectorAll('img[class^=note-slider-img]');
  2327. for(let i=0; i< arr1.length; i++){
  2328. let mainImgUrl = arr1[i].src;
  2329. let result = regex.exec(mainImgUrl);
  2330. if(result){
  2331. mainImgUrl = mainImgUrl.replace(result[0], '.'+result[1]);
  2332. }
  2333. if(!authority && i < execNum){
  2334. outObj.mainImg.push(mainImgUrl);
  2335. }
  2336. if(authority){
  2337. outObj.mainImg.push(mainImgUrl);
  2338. }
  2339. }
  2340. // 视频
  2341. let arr5 = document.querySelectorAll('video.lib-video');
  2342. for(let i=0; i< arr5.length; i++){
  2343. if(outObj.video.indexOf(arr5[i].src) == -1){
  2344. if(!authority && i < execNum){
  2345. outObj.video.push(arr5[i].src);
  2346. }
  2347. if(authority){
  2348. outObj.video.push(arr5[i].src);
  2349. }
  2350. }
  2351. }
  2352. return outObj;
  2353. }, authority, this.execNum);
  2354. if(imgInfo.mainImg.length >= 3 && authority){
  2355. imgInfo.mainImg = imgInfo.mainImg.slice(1, imgInfo.mainImg.length-1); //小红书轮播图第一个/最后一个和内容重复去掉
  2356. }
  2357. imgInfo.video = responseVideo;
  2358. if(this.settingArr.indexOf('mainImg') > -1){
  2359. // 主图下载
  2360. for(let j = 0; j < imgInfo.mainImg.length; j++){
  2361. let fileName = imgInfo.mainImg[j].split('/').pop();
  2362. if(fileName){
  2363. let queryIndex = fileName.indexOf('?');
  2364. if (queryIndex !== -1) {
  2365. fileName = fileName.substr(0, queryIndex);
  2366. }
  2367. let num = Number(j) + 1;
  2368. let suffix = '.jpg';
  2369. if(fileName.lastIndexOf('.') > -1){
  2370. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2371. }
  2372. let outputPath = urlInfo.newPath + '\\文章图' + num + suffix;
  2373. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  2374. }
  2375. }
  2376. }
  2377. if(this.settingArr.indexOf('video') > -1){
  2378. //视频下载
  2379. for(let j = 0; j < imgInfo.video.length; j++){
  2380. let fileName = imgInfo.video[j].split('/').pop();
  2381. if(fileName){
  2382. let queryIndex = fileName.indexOf('?');
  2383. if (queryIndex !== -1) {
  2384. fileName = fileName.substr(0, queryIndex);
  2385. }
  2386. let num = Number(j) + 1;
  2387. let suffix = '.mp4';
  2388. if(fileName.lastIndexOf('.') > -1){
  2389. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2390. }
  2391. let outputPath = urlInfo.newPath + '\\视频' + num + suffix;
  2392. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2393. }
  2394. }
  2395. }
  2396. await page.close();
  2397. urlInfo.status = '4';
  2398. resolve(true);
  2399. this.loading = false;
  2400. }catch(e){
  2401. urlInfo.status = '5';
  2402. reject(e);
  2403. this.showError(e);
  2404. }
  2405. })();
  2406. });
  2407. },
  2408. /**************************阿里国际商品图片下载*******************************************************************************************/
  2409. // 6 - 阿里国际 - 扫描并下载图片
  2410. async aliguojiScanImg(browser, page, urlInfo, authority){
  2411. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2412. const imgInfo = await page.evaluate((authority, execNum) => {
  2413. let outObj = {
  2414. mainImg: [],
  2415. detailImg: [],
  2416. skuImg: [],
  2417. commentImg: [],
  2418. video: []
  2419. };
  2420. //主图
  2421. let arr1 = document.querySelectorAll('.module_productImage img[class*="-object-contain"]');
  2422. for(let i=0; i< arr1.length; i++){
  2423. if(!authority && i < execNum){
  2424. outObj.mainImg.push(arr1[i].src);
  2425. }
  2426. if(authority){
  2427. outObj.mainImg.push(arr1[i].src);
  2428. }
  2429. }
  2430. //sku图片
  2431. let arr2 = document.querySelectorAll('.module_sku img[class*="-object-contain"]');
  2432. for(let i=0; i< arr2.length; i++){
  2433. if(!authority && i < execNum){
  2434. outObj.skuImg.push(arr2[i].src);
  2435. }
  2436. if(authority){
  2437. outObj.skuImg.push(arr2[i].src);
  2438. }
  2439. }
  2440. //详情图片
  2441. let arr3 = document.querySelectorAll('#description-layout img');
  2442. // if(arr3.length == 0){
  2443. // if(document.getElementById('description') && document.getElementById('description').querySelector('.html-description')){
  2444. // arr3 = document.getElementById('description').querySelector('.html-description').shadowRoot.querySelectorAll('img');
  2445. // }
  2446. // }
  2447. if(arr3.length == 0){
  2448. if(document.querySelector('#description-layout').querySelector('iframe')){
  2449. arr3 = document.querySelector('#description-layout').querySelector('iframe').contentDocument.querySelectorAll('img')
  2450. }
  2451. }
  2452. for(let i=0; i< arr3.length; i++){
  2453. if(!authority && i < execNum){
  2454. outObj.detailImg.push(arr3[i].src);
  2455. }
  2456. if(authority){
  2457. outObj.detailImg.push(arr3[i].src);
  2458. }
  2459. }
  2460. // 视频
  2461. let arr5 = document.querySelectorAll('video');
  2462. for(let i=0; i< arr5.length; i++){
  2463. if(arr5[i].src && outObj.video.indexOf(arr5[i].src) == -1){
  2464. if(!authority && i < execNum){
  2465. outObj.video.push(arr5[i].src);
  2466. }
  2467. if(authority){
  2468. outObj.video.push(arr5[i].src);
  2469. }
  2470. }
  2471. }
  2472. return outObj;
  2473. }, authority, this.execNum);
  2474. // 主图下载
  2475. if(this.settingArr.indexOf('mainImg') > -1){
  2476. for(let j = 0; j < imgInfo.mainImg.length; j++){
  2477. let fileName = imgInfo.mainImg[j].split('/').pop();
  2478. if(fileName){
  2479. let queryIndex = fileName.indexOf('?');
  2480. if (queryIndex !== -1) {
  2481. fileName = fileName.substr(0, queryIndex);
  2482. }
  2483. let num = Number(j) + 1;
  2484. let suffix = '';
  2485. if(fileName.lastIndexOf('.') > -1){
  2486. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2487. }
  2488. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  2489. fs.mkdirSync(urlInfo.newPath + '\\主图');
  2490. }
  2491. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  2492. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  2493. }
  2494. }
  2495. }
  2496. // sku图片下载
  2497. if(this.settingArr.indexOf('skuImg') > -1){
  2498. for(let j = 0; j < imgInfo.skuImg.length; j++){
  2499. let fileName = imgInfo.skuImg[j].split('/').pop();
  2500. if(fileName){
  2501. let queryIndex = fileName.indexOf('?');
  2502. if (queryIndex !== -1) {
  2503. fileName = fileName.substr(0, queryIndex);
  2504. }
  2505. let num = Number(j) + 1;
  2506. let suffix = '';
  2507. if(fileName.lastIndexOf('.') > -1){
  2508. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2509. }
  2510. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  2511. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  2512. }
  2513. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  2514. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  2515. }
  2516. }
  2517. }
  2518. //详情图下载
  2519. if(this.settingArr.indexOf('detailImg') > -1){
  2520. for(let j = 0; j < imgInfo.detailImg.length; j++){
  2521. let fileName = imgInfo.detailImg[j].split('/').pop();
  2522. if(fileName){
  2523. let queryIndex = fileName.indexOf('?');
  2524. if (queryIndex !== -1) {
  2525. fileName = fileName.substr(0, queryIndex);
  2526. }
  2527. let num = Number(j) + 1;
  2528. let suffix = '';
  2529. if(fileName.lastIndexOf('.') > -1){
  2530. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2531. }
  2532. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  2533. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  2534. }
  2535. let outputPath = urlInfo.newPath + '\\详情图\\' + '详情图' + num + suffix;
  2536. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  2537. }
  2538. }
  2539. }
  2540. //视频下载
  2541. if(this.settingArr.indexOf('video') > -1){
  2542. for(let j = 0; j < imgInfo.video.length; j++){
  2543. let fileName = imgInfo.video[j].split('/').pop();
  2544. if(fileName){
  2545. let queryIndex = fileName.indexOf('?');
  2546. if (queryIndex !== -1) {
  2547. fileName = fileName.substr(0, queryIndex);
  2548. }
  2549. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  2550. fs.mkdirSync(urlInfo.newPath + '\\视频');
  2551. }
  2552. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  2553. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2554. }
  2555. }
  2556. }
  2557. await page.close(); // 关闭页面但不关闭浏览器
  2558. },
  2559. /*********************************************************************************************************************/
  2560. /**************************百度爱采购商品图片下载*******************************************************************************************/
  2561. // 7 - 百度爱采购 - 扫描并下载图片
  2562. async acaigouScanImg(browser, page, urlInfo, authority){
  2563. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2564. const imgInfo = await page.evaluate((authority, execNum) => {
  2565. let outObj = {
  2566. mainImg: [],
  2567. detailImg: [],
  2568. skuImg: [],
  2569. commentImg: [],
  2570. video: []
  2571. };
  2572. //主图
  2573. let arr1 = document.querySelectorAll('.album .img-container .img');
  2574. for(let i=0; i< arr1.length; i++){
  2575. let src = window.getComputedStyle(arr1[i]).backgroundImage.replace(/url\(["']?(.+?)["']?\)/i, '$1');
  2576. if(src && outObj.mainImg.indexOf(src) == -1){
  2577. if(!authority && i < execNum){
  2578. outObj.mainImg.push(src);
  2579. }
  2580. if(authority){
  2581. outObj.mainImg.push(src);
  2582. }
  2583. }
  2584. }
  2585. //sku图片
  2586. // let arr2 = document.querySelectorAll('.module_sku img[class*="-object-contain"]');
  2587. // for(let i=0; i< arr2.length; i++){
  2588. // if(!authority && i < execNum){
  2589. // outObj.skuImg.push(arr2[i].src);
  2590. // }
  2591. // if(authority){
  2592. // outObj.skuImg.push(arr2[i].src);
  2593. // }
  2594. // }
  2595. //详情图片
  2596. let arr3 = document.querySelectorAll('.details .questionable-detail img');
  2597. for(let i=0; i< arr3.length; i++){
  2598. if(!authority && i < execNum){
  2599. outObj.detailImg.push(arr3[i].src);
  2600. }
  2601. if(authority){
  2602. outObj.detailImg.push(arr3[i].src);
  2603. }
  2604. }
  2605. // 视频
  2606. let arr5 = document.querySelectorAll('.album video');
  2607. for(let i=0; i< arr5.length; i++){
  2608. if(arr5[i].src && outObj.video.indexOf(arr5[i].src) == -1){
  2609. if(!authority && i < execNum){
  2610. outObj.video.push(arr5[i].src);
  2611. }
  2612. if(authority){
  2613. outObj.video.push(arr5[i].src);
  2614. }
  2615. }
  2616. }
  2617. return outObj;
  2618. }, authority, this.execNum);
  2619. // 主图下载
  2620. if(this.settingArr.indexOf('mainImg') > -1){
  2621. for(let j = 0; j < imgInfo.mainImg.length; j++){
  2622. let fileName = imgInfo.mainImg[j].split('/').pop();
  2623. if(fileName){
  2624. let queryIndex = fileName.indexOf('?');
  2625. if (queryIndex !== -1) {
  2626. fileName = fileName.substr(0, queryIndex);
  2627. }
  2628. let num = Number(j) + 1;
  2629. let suffix = '.webp';
  2630. if(fileName.lastIndexOf('.') > -1){
  2631. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2632. }
  2633. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  2634. fs.mkdirSync(urlInfo.newPath + '\\主图');
  2635. }
  2636. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  2637. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  2638. }
  2639. }
  2640. }
  2641. // sku图片下载
  2642. if(this.settingArr.indexOf('skuImg') > -1){
  2643. for(let j = 0; j < imgInfo.skuImg.length; j++){
  2644. let fileName = imgInfo.skuImg[j].split('/').pop();
  2645. if(fileName){
  2646. let queryIndex = fileName.indexOf('?');
  2647. if (queryIndex !== -1) {
  2648. fileName = fileName.substr(0, queryIndex);
  2649. }
  2650. let num = Number(j) + 1;
  2651. let suffix = '';
  2652. if(fileName.lastIndexOf('.') > -1){
  2653. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2654. }
  2655. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  2656. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  2657. }
  2658. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  2659. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  2660. }
  2661. }
  2662. }
  2663. //详情图下载
  2664. if(this.settingArr.indexOf('detailImg') > -1){
  2665. for(let j = 0; j < imgInfo.detailImg.length; j++){
  2666. let fileName = imgInfo.detailImg[j].split('/').pop();
  2667. if(fileName){
  2668. let queryIndex = fileName.indexOf('?');
  2669. if (queryIndex !== -1) {
  2670. fileName = fileName.substr(0, queryIndex);
  2671. }
  2672. let num = Number(j) + 1;
  2673. let suffix = '.webp';
  2674. if(fileName.lastIndexOf('.') > -1){
  2675. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2676. }
  2677. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  2678. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  2679. }
  2680. let outputPath = urlInfo.newPath + '\\详情图\\' + '详情图' + num + suffix;
  2681. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  2682. }
  2683. }
  2684. }
  2685. //视频下载
  2686. if(this.settingArr.indexOf('video') > -1){
  2687. for(let j = 0; j < imgInfo.video.length; j++){
  2688. let fileName = imgInfo.video[j].split('/').pop();
  2689. if(fileName){
  2690. let queryIndex = fileName.indexOf('?');
  2691. if (queryIndex !== -1) {
  2692. fileName = fileName.substr(0, queryIndex);
  2693. }
  2694. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  2695. fs.mkdirSync(urlInfo.newPath + '\\视频');
  2696. }
  2697. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  2698. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2699. }
  2700. }
  2701. }
  2702. await page.close(); // 关闭页面但不关闭浏览器
  2703. },
  2704. /*********************************************************************************************************************/
  2705. /**************************亚马逊商品图片下载*******************************************************************************************/
  2706. // 8 - 亚马逊 - 扫描并下载图片
  2707. async amazonScanImg(browser, page, urlInfo, authority){
  2708. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2709. const imgInfo = await page.evaluate((authority, execNum) => {
  2710. let outObj = {
  2711. mainImg: [],
  2712. detailImg: [],
  2713. skuImg: [],
  2714. commentImg: [],
  2715. video: []
  2716. };
  2717. //主图
  2718. let arr1 = document.querySelectorAll('#leftCol img.a-dynamic-image');
  2719. for(let i=0; i< arr1.length; i++){
  2720. if(!authority && i < execNum){
  2721. outObj.mainImg.push(arr1[i].src);
  2722. }
  2723. if(authority){
  2724. outObj.mainImg.push(arr1[i].src);
  2725. }
  2726. }
  2727. //sku图片
  2728. let arr2 = document.querySelectorAll('.module_sku img[class*="-object-contain"]');
  2729. for(let i=0; i< arr2.length; i++){
  2730. if(!authority && i < execNum){
  2731. outObj.skuImg.push(arr2[i].src);
  2732. }
  2733. if(authority){
  2734. outObj.skuImg.push(arr2[i].src);
  2735. }
  2736. }
  2737. //详情图片
  2738. let arr3 = document.querySelectorAll('#description-layout img');
  2739. // if(arr3.length == 0){
  2740. // if(document.getElementById('description') && document.getElementById('description').querySelector('.html-description')){
  2741. // arr3 = document.getElementById('description').querySelector('.html-description').shadowRoot.querySelectorAll('img');
  2742. // }
  2743. // }
  2744. for(let i=0; i< arr3.length; i++){
  2745. if(!authority && i < execNum){
  2746. outObj.detailImg.push(arr3[i].src);
  2747. }
  2748. if(authority){
  2749. outObj.detailImg.push(arr3[i].src);
  2750. }
  2751. }
  2752. // 视频
  2753. let arr5 = document.querySelectorAll('#description-layout video');
  2754. for(let i=0; i< arr5.length; i++){
  2755. if(arr5[i].src && outObj.video.indexOf(arr5[i].src) == -1){
  2756. if(!authority && i < execNum){
  2757. outObj.video.push(arr5[i].src);
  2758. }
  2759. if(authority){
  2760. outObj.video.push(arr5[i].src);
  2761. }
  2762. }
  2763. }
  2764. return outObj;
  2765. }, authority, this.execNum);
  2766. // 主图下载
  2767. if(this.settingArr.indexOf('mainImg') > -1){
  2768. for(let j = 0; j < imgInfo.mainImg.length; j++){
  2769. let fileName = imgInfo.mainImg[j].split('/').pop();
  2770. if(fileName){
  2771. let queryIndex = fileName.indexOf('?');
  2772. if (queryIndex !== -1) {
  2773. fileName = fileName.substr(0, queryIndex);
  2774. }
  2775. let num = Number(j) + 1;
  2776. let suffix = '';
  2777. if(fileName.lastIndexOf('.') > -1){
  2778. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2779. }
  2780. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  2781. fs.mkdirSync(urlInfo.newPath + '\\主图');
  2782. }
  2783. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  2784. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  2785. }
  2786. }
  2787. }
  2788. // sku图片下载
  2789. if(this.settingArr.indexOf('skuImg') > -1){
  2790. for(let j = 0; j < imgInfo.skuImg.length; j++){
  2791. let fileName = imgInfo.skuImg[j].split('/').pop();
  2792. if(fileName){
  2793. let queryIndex = fileName.indexOf('?');
  2794. if (queryIndex !== -1) {
  2795. fileName = fileName.substr(0, queryIndex);
  2796. }
  2797. let num = Number(j) + 1;
  2798. let suffix = '';
  2799. if(fileName.lastIndexOf('.') > -1){
  2800. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2801. }
  2802. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  2803. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  2804. }
  2805. let outputPath = urlInfo.newPath + '\\sku图\\sku图' + num + suffix;
  2806. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  2807. }
  2808. }
  2809. }
  2810. //详情图下载
  2811. if(this.settingArr.indexOf('detailImg') > -1){
  2812. for(let j = 0; j < imgInfo.detailImg.length; j++){
  2813. let fileName = imgInfo.detailImg[j].split('/').pop();
  2814. if(fileName){
  2815. let queryIndex = fileName.indexOf('?');
  2816. if (queryIndex !== -1) {
  2817. fileName = fileName.substr(0, queryIndex);
  2818. }
  2819. let num = Number(j) + 1;
  2820. let suffix = '';
  2821. if(fileName.lastIndexOf('.') > -1){
  2822. suffix = fileName.substr(fileName.lastIndexOf('.'));
  2823. }
  2824. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  2825. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  2826. }
  2827. let outputPath = urlInfo.newPath + '\\详情图\\' + '详情图' + num + suffix;
  2828. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  2829. }
  2830. }
  2831. }
  2832. //视频下载
  2833. if(this.settingArr.indexOf('video') > -1){
  2834. for(let j = 0; j < imgInfo.video.length; j++){
  2835. let fileName = imgInfo.video[j].split('/').pop();
  2836. if(fileName){
  2837. let queryIndex = fileName.indexOf('?');
  2838. if (queryIndex !== -1) {
  2839. fileName = fileName.substr(0, queryIndex);
  2840. }
  2841. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  2842. fs.mkdirSync(urlInfo.newPath + '\\视频');
  2843. }
  2844. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  2845. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  2846. }
  2847. }
  2848. }
  2849. await page.close(); // 关闭页面但不关闭浏览器
  2850. },
  2851. /*********************************************************************************************************************/
  2852. /***********拼多多商品下载**********/
  2853. // 检查pdd登录状态
  2854. checkPddLogin(){
  2855. this.checkLoading = true;
  2856. this.pddStatus = 1;
  2857. return new Promise((resolve, reject) => {
  2858. (async () => {
  2859. try{
  2860. if(this.loginBrowser){
  2861. await this.loginBrowser.close();
  2862. this.loginBrowser = null;
  2863. }
  2864. puppeteer.use(StealthPlugin());
  2865. this.loginBrowser = await puppeteer.launch({
  2866. executablePath: this.initPath(),
  2867. userDataDir: this.initDataDir(),
  2868. args: [
  2869. '--start-maximized',
  2870. '--no-sandbox',
  2871. '--disable-setuid-sandbox',
  2872. '--disable-blink-features=AutomationControlled',
  2873. '--window-size=1280,800'
  2874. ],
  2875. });
  2876. const page = await this.loginBrowser.newPage();
  2877. await page.setViewport({ width: 1280, height: 800 });
  2878. let testUrl = "https://mobile.yangkeduo.com/personal.html";
  2879. await page.goto(testUrl, {waitUntil : 'networkidle2'});
  2880. let loginBtn = await page.$('.login-box');
  2881. if(loginBtn){
  2882. let searchValue = await page.$eval('.login-box', el => el.innerText);
  2883. if(searchValue == '手机登录' || searchValue.indexOf('登录') > -1){
  2884. this.pddStatus = 3; //未登录
  2885. }else{
  2886. this.pddStatus = 2;
  2887. }
  2888. }else{
  2889. this.pddStatus = 2;
  2890. }
  2891. resolve(this.pddStatus);
  2892. this.checkLoading = false;
  2893. await this.loginBrowser.close();
  2894. this.loginBrowser = null;
  2895. }catch(e){
  2896. this.checkLoading = false;
  2897. reject(3);
  2898. this.showError(e);
  2899. }
  2900. })();
  2901. });
  2902. },
  2903. // 9-pdd图片下载
  2904. async pddDownload(urlInfo, pddBrowser){
  2905. let task = await new Promise((resolve,reject) =>{
  2906. (async () => {
  2907. try{
  2908. let authority = this.$refs.headerRef.authority.isAuthority;
  2909. let number = 0;
  2910. urlInfo.status = '2';
  2911. urlInfo.num = 0;
  2912. const page = await pddBrowser.newPage();
  2913. await page.goto(urlInfo.url, {waitUntil : 'networkidle2'});
  2914. if(urlInfo.title){
  2915. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title)) {
  2916. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  2917. } else {
  2918. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title);
  2919. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + urlInfo.title;
  2920. }
  2921. }else{
  2922. // 获取商品标题
  2923. let titleHandle = await page.$$('span.enable-select');
  2924. if(titleHandle && titleHandle.length > 0){
  2925. let titleValue = await page.$eval('span.enable-select', el => el.innerText);
  2926. await this.getTitle(page, urlInfo, titleValue); // 生成页面标题对应的文件夹
  2927. }else{
  2928. await this.getTitle(page, urlInfo, '拼多多商品-'+new Date().getTime()); // 生成页面标题对应的文件夹
  2929. }
  2930. }
  2931. urlInfo.status = '3';
  2932. // 被平台限制浏览
  2933. let notSale = await page.$$('.not-sale');
  2934. if(notSale && notSale.length > 0){
  2935. let notValue = await page.$eval('.not-sale', el => el.innerText);
  2936. if(notValue.indexOf('商品已售罄') > -1 || notValue.indexOf('推荐以下') > -1){
  2937. await page.close();
  2938. urlInfo.status = '7';
  2939. resolve(true);
  2940. this.loading = false;
  2941. return false;
  2942. }
  2943. }
  2944. //detailImg:详情图;skuImg:sku图片;commentImg: 评论图;video: 视频
  2945. const imgInfo = await page.evaluate((authority, execNum) => {
  2946. let outObj = {
  2947. mainImg: [],
  2948. detailImg: [],
  2949. skuImg: [],
  2950. commentImg: [],
  2951. video: [],
  2952. skuName: []
  2953. };
  2954. let skuHandle = document.querySelector('div[class*=sku-plus] img');
  2955. if(skuHandle){
  2956. skuHandle.click({force: true});
  2957. }
  2958. //主图
  2959. let mainDiv = document.querySelectorAll('#main > div > div')[0];
  2960. let arr1 = mainDiv.querySelectorAll('img');
  2961. for(let i=0; i< arr1.length; i++){
  2962. if(i > 0 && i < arr1.length-1){ // 去掉首尾重复
  2963. let mainImgUrl = arr1[i].src || arr1[i].dataset.src;
  2964. if(!authority && i < execNum){
  2965. outObj.mainImg.push(mainImgUrl);
  2966. }
  2967. if(authority){
  2968. outObj.mainImg.push(mainImgUrl);
  2969. }
  2970. }
  2971. }
  2972. //sku
  2973. let arr2 = document.querySelectorAll('#skuImageSlider img');
  2974. for(let i=0; i< arr2.length; i++){
  2975. if(i > 0 && i < arr2.length-1){ // 去掉首尾重复 -去掉重复图片
  2976. let skuImgUrl = arr2[i].src || arr2[i].dataset.src;
  2977. if(outObj.skuImg.indexOf(skuImgUrl) == -1){
  2978. let nextEle = arr2[i].parentElement.nextElementSibling;
  2979. let num = Number(i) + 1;
  2980. let name = 'sku图' + num + '.jpeg';
  2981. if(nextEle){
  2982. name = nextEle.innerText.split('\n')[0];
  2983. name = name.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
  2984. }
  2985. if(!authority && i < execNum){
  2986. outObj.skuImg.push(skuImgUrl);
  2987. outObj.skuName.push(name);
  2988. }
  2989. if(authority){
  2990. outObj.skuImg.push(skuImgUrl);
  2991. outObj.skuName.push(name);
  2992. }
  2993. }
  2994. }
  2995. }
  2996. //详情图
  2997. let arr3 = document.querySelectorAll('img[class*=pdd-lazy-image][aria-label="查看图片"]');
  2998. if(arr3.length == 0){
  2999. arr3 = [];
  3000. let imgArr = document.querySelectorAll('img[class*=pdd-lazy-image]');
  3001. for(let m = 0; m < imgArr.length; m++){
  3002. if(imgArr[m].parentElement.ariaLabel == '点击查看大图'){
  3003. arr3.push(imgArr[m]);
  3004. }
  3005. }
  3006. }
  3007. for(let i=0; i< arr3.length; i++){
  3008. let detailImgUrl = arr3[i].src || arr3[i].dataset.src;
  3009. if(!authority && i < execNum){
  3010. outObj.detailImg.push(detailImgUrl);
  3011. }
  3012. if(authority){
  3013. outObj.detailImg.push(detailImgUrl);
  3014. }
  3015. }
  3016. // 视频
  3017. let arr5 = document.querySelectorAll('video');
  3018. for(let i=0; i< arr5.length; i++){
  3019. if(outObj.video.indexOf(arr5[i].src) == -1){
  3020. if(!authority && i < execNum){
  3021. outObj.video.push(arr5[i].src);
  3022. }
  3023. if(authority){
  3024. outObj.video.push(arr5[i].src);
  3025. }
  3026. }
  3027. }
  3028. return outObj;
  3029. }, authority, this.execNum);
  3030. // 主图下载
  3031. if(this.settingArr.indexOf('mainImg') > -1){
  3032. for(let j = 0; j < imgInfo.mainImg.length; j++){
  3033. let imgUrl = imgInfo.mainImg[j];
  3034. let queryIndex = imgInfo.mainImg[j].indexOf('?');
  3035. if (queryIndex !== -1) {
  3036. imgUrl = imgUrl.substr(0, queryIndex);
  3037. }
  3038. let fileName = imgUrl.split('/').pop();
  3039. let num = Number(j) + 1;
  3040. let suffix = '.jpg';
  3041. if(fileName.lastIndexOf('.') > -1){
  3042. suffix = fileName.substr(fileName.lastIndexOf('.'));
  3043. }
  3044. if (!fs.existsSync(urlInfo.newPath + '\\主图')) {
  3045. fs.mkdirSync(urlInfo.newPath + '\\主图');
  3046. }
  3047. let outputPath = urlInfo.newPath + '\\主图\\主图' + num + suffix;
  3048. await this.downloadImage(imgInfo.mainImg[j], outputPath, urlInfo);
  3049. }
  3050. }
  3051. // sku图片下载
  3052. if(this.settingArr.indexOf('skuImg') > -1){
  3053. for(let j = 0; j < imgInfo.skuImg.length; j++){
  3054. let imgUrl = imgInfo.skuImg[j];
  3055. let queryIndex = imgInfo.skuImg[j].indexOf('?');
  3056. if (queryIndex !== -1) {
  3057. imgUrl = imgUrl.substr(0, queryIndex);
  3058. }
  3059. let fileName = imgUrl.split('/').pop();
  3060. let num = Number(j) + 1;
  3061. let suffix = '.jpg';
  3062. if(fileName.lastIndexOf('.') > -1){
  3063. suffix = fileName.substr(fileName.lastIndexOf('.'));
  3064. }
  3065. if (!fs.existsSync(urlInfo.newPath + '\\sku图')) {
  3066. fs.mkdirSync(urlInfo.newPath + '\\sku图');
  3067. }
  3068. let outputPath = urlInfo.newPath + '\\sku图\\' + imgInfo.skuName[j] + suffix;
  3069. await this.downloadImage(imgInfo.skuImg[j], outputPath, urlInfo);
  3070. }
  3071. }
  3072. //详情图下载
  3073. if(this.settingArr.indexOf('detailImg') > -1){
  3074. for(let j = 0; j < imgInfo.detailImg.length; j++){
  3075. let imgUrl = imgInfo.detailImg[j];
  3076. let queryIndex = imgInfo.detailImg[j].indexOf('?');
  3077. if (queryIndex !== -1) {
  3078. imgUrl = imgUrl.substr(0, queryIndex);
  3079. }
  3080. let fileName = imgUrl.split('/').pop();
  3081. let num = Number(j) + 1;
  3082. let suffix = '.jpg';
  3083. if(fileName.lastIndexOf('.') > -1){
  3084. suffix = fileName.substr(fileName.lastIndexOf('.'));
  3085. }
  3086. if (!fs.existsSync(urlInfo.newPath + '\\详情图')) {
  3087. fs.mkdirSync(urlInfo.newPath + '\\详情图');
  3088. }
  3089. let outputPath = urlInfo.newPath + '\\详情图\\详情图' + num + suffix;
  3090. await this.downloadImage(imgInfo.detailImg[j], outputPath, urlInfo);
  3091. }
  3092. }
  3093. //视频下载
  3094. if(this.settingArr.indexOf('video') > -1){
  3095. for(let j = 0; j < imgInfo.video.length; j++){
  3096. let fileName = imgInfo.video[j].split('/').pop();
  3097. if(fileName){
  3098. let queryIndex = fileName.indexOf('?');
  3099. if (queryIndex !== -1) {
  3100. fileName = fileName.substr(0, queryIndex);
  3101. }
  3102. if (!fs.existsSync(urlInfo.newPath + '\\视频')) {
  3103. fs.mkdirSync(urlInfo.newPath + '\\视频');
  3104. }
  3105. let outputPath = urlInfo.newPath + '\\视频\\' + fileName;
  3106. await this.downloadImage(imgInfo.video[j], outputPath, urlInfo);
  3107. }
  3108. }
  3109. }
  3110. await page.close();
  3111. urlInfo.status = '4';
  3112. resolve(true);
  3113. this.loading = false;
  3114. }catch(e){
  3115. urlInfo.status = '5';
  3116. reject(e);
  3117. this.showError(e);
  3118. }
  3119. })();
  3120. });
  3121. },
  3122. //
  3123. downloadExample(){
  3124. let url = 'https://www.xingyousoft.com/soft/XYCapture/example.xlsx';
  3125. if (!fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName)) {
  3126. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName);
  3127. }
  3128. let path = this.downloadDir + separator + pjson.softInfo.softName + '\\链接模板下载.xlsx';
  3129. this.downloadImage(url, path, 'example');
  3130. },
  3131. // 下载网址链接的图片
  3132. async downloadImage(imageUrl, outputPath, urlInfo) {
  3133. let _this = this;
  3134. let received_bytes = 0;
  3135. let total_bytes = 0;
  3136. try {
  3137. let req = request({
  3138. method: 'GET', uri: imageUrl, strictSSL: false
  3139. });
  3140. let out = fs.createWriteStream(outputPath);
  3141. req.pipe(out);
  3142. return new Promise((resolve, reject) => {
  3143. req.on('response', (data) => {
  3144. total_bytes = parseInt(data.headers['content-length']);
  3145. const status = data.statusCode;
  3146. if (status < 200 || status >= 300) {
  3147. //reject(false);
  3148. this.$notify.error({
  3149. title: '网络图片访问异常!- 1',
  3150. message: imageUrl.slice(0,50)
  3151. });
  3152. }else if(isNaN(total_bytes)){
  3153. //reject(false);
  3154. this.$notify.error({
  3155. title: '网络图片访问异常!- 2',
  3156. message: imageUrl.slice(0,50)
  3157. });
  3158. }else{
  3159. // console.log('下载中...')
  3160. }
  3161. });
  3162. req.on('data', (chunk) => {
  3163. received_bytes += chunk.length;
  3164. });
  3165. req.on('end', ()=> {
  3166. if(urlInfo != 'example'){
  3167. urlInfo.num += 1;
  3168. }else{
  3169. this.$msgbox({
  3170. title: '消息',
  3171. message: '模板下载成功,保存位置:' + this.downloadDir + separator + pjson.softInfo.softName,
  3172. showCancelButton: true,
  3173. confirmButtonText: '去查看',
  3174. cancelButtonText: '取消',
  3175. }).then(action => {
  3176. this.openFolder();
  3177. }).catch(action => {
  3178. });
  3179. }
  3180. //console.log('下载完成', outputPath)
  3181. resolve(true);
  3182. });
  3183. });
  3184. } catch (error) {
  3185. console.error(imageUrl, `Failed to download image: ${error.message}`);
  3186. throw error;
  3187. }
  3188. },
  3189. // 获取页面标题 - 生成对应的文件夹
  3190. async getTitle(page, urlInfo, tagStr){
  3191. // 已页面标题作为新建文件夹,保留前50个字
  3192. let title = await page.title();
  3193. if(!title){
  3194. title = '无标题-'+new Date().getTime();
  3195. }
  3196. if(tagStr){
  3197. title = tagStr.replace(/\.\.\./g, '');
  3198. }
  3199. if(title){
  3200. title = title.substring(0, 50).trim();
  3201. if(this.containsAnyChar(title, ['\\', '/', ':', '*', '?', '"', '<', '>', '|'])){ //判断是否含有特殊字符
  3202. title = title.replace(/[\\|/|:|*|?|"|<|>||]/g, "");
  3203. }
  3204. if (fs.existsSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title)) {
  3205. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
  3206. } else {
  3207. fs.mkdirSync(this.downloadDir + separator + pjson.softInfo.softName + separator + title);
  3208. urlInfo.newPath = this.downloadDir + separator + pjson.softInfo.softName + separator + title;
  3209. }
  3210. }
  3211. },
  3212. // 下载base64位的图片
  3213. async downloadBaseImage(base64String, outputPath, urlInfo) {
  3214. const buffer = Buffer.from(base64String, 'base64');
  3215. const writeStream = fs.createWriteStream(outputPath);
  3216. writeStream.write(buffer);
  3217. writeStream.end();
  3218. writeStream.on('finish', () => {
  3219. urlInfo.num += 1;
  3220. });
  3221. // 监听错误事件
  3222. writeStream.on('error', (err) => {
  3223. console.error('base64位写入文件时出错:', err);
  3224. });
  3225. },
  3226. // 错误提示
  3227. showError(e){
  3228. let str = '';
  3229. if(e.toString().indexOf('ERR_NAME_NOT_RESOLVE') > -1){
  3230. str = '无法解析该网址,请查看网址是否正确!-1';
  3231. }else if(e.toString().indexOf('Cannot navigate to invalid URL') > -1){
  3232. str = '无效的网址,请查看网址格式是否正确!-2';
  3233. }else if(e.toString().indexOf('ERR_CONNECTION_TIMED_OUT') > -1){
  3234. str = '链接请求超时,请查看网络状态!-3';
  3235. }else if(e.toString().indexOf('TimeoutError') > -1){
  3236. str = '链接请求超时,请查看网络状态!-4';
  3237. }else if(e.toString().indexOf('operation not permitted') > -1){
  3238. str = '权限受限,请以管理员权限运行软件!-5';
  3239. }else if(e.toString().indexOf('browser has disconnected') > -1){
  3240. str = '内置浏览器已关闭!-6';
  3241. }else if(e.toString().indexOf('Failed to launch the browser') > -1){
  3242. str = '请先关闭内置浏览器!-7';
  3243. }else{
  3244. str = e.toString();
  3245. //console.log(e);
  3246. }
  3247. this.loading = false;
  3248. this.$notify.error({
  3249. title: '提示',
  3250. message: str
  3251. });
  3252. },
  3253. // 是否包含特殊字符
  3254. containsAnyChar(str, charsArray) {
  3255. for (let i = 0; i < charsArray.length; i++) {
  3256. if (str.includes(charsArray[i])) {
  3257. return true;
  3258. }
  3259. }
  3260. return false;
  3261. },
  3262. // 随机生成字符
  3263. randomString(length) {
  3264. let result = '';
  3265. const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  3266. const charactersLength = characters.length;
  3267. for (let i = 0; i < length; i++ ) {
  3268. result += characters.charAt(Math.floor(Math.random() * charactersLength));
  3269. }
  3270. return result;
  3271. }
  3272. }
  3273. };
  3274. </script>
  3275. <style lang="scss">
  3276. @import "../assets/css/fontx/iconfont.css";
  3277. @import "../assets/css/home.scss";
  3278. .ivu-input-number-controls-outside-btn i {
  3279. font-weight: 800;
  3280. }
  3281. .update-point {
  3282. display: inline-block;
  3283. width: 8px;
  3284. height: 8px;
  3285. border-radius: 8px;
  3286. background: #ff0000;
  3287. top: 14px;
  3288. position: absolute;
  3289. left: -13px;
  3290. }
  3291. .menu-item {
  3292. padding: 8px 0;
  3293. font-size: 14px;
  3294. .iconfont {
  3295. font-size: 32px;
  3296. }
  3297. &:hover,
  3298. &.active {
  3299. color: #ed4014;
  3300. }
  3301. }
  3302. .ivu-progress-show-info .ivu-progress-outer {
  3303. padding-right: 40px !important;
  3304. margin-right: -40px !important;
  3305. }
  3306. .tips {
  3307. text-align: center;
  3308. padding: 10px 0;
  3309. color: #ed4014;
  3310. font-size: 12px;
  3311. }
  3312. .handle-desc {
  3313. display: inline-block;
  3314. width: calc(100% - 100px);
  3315. overflow: hidden;
  3316. }
  3317. .ivu-menu-submenu-title {
  3318. font-weight: 600;
  3319. }
  3320. .ivu-menu .ivu-menu-item {
  3321. line-height: 1;
  3322. }
  3323. // new-el
  3324. .el-menu {
  3325. border-right: none !important;
  3326. }
  3327. .cmenu-item {
  3328. padding: 0 20px 20px;
  3329. margin-bottom: 15px;
  3330. .cmenu-title {
  3331. font-size: 18px;
  3332. font-weight: 600;
  3333. padding-bottom: 20px;
  3334. }
  3335. .citem-nav {
  3336. text-align: center;
  3337. border-radius: 10px;
  3338. min-height: 110px;
  3339. padding: 15px 0;
  3340. background-color: #fff;
  3341. font-size: 15px;
  3342. cursor: pointer;
  3343. &.bg-linear1 {
  3344. color: #fff;
  3345. font-size: 20px;
  3346. background: linear-gradient(to right bottom, #2A56CA, #5795F4);
  3347. }
  3348. &.bg-linear2 {
  3349. color: #fff;
  3350. font-size: 20px;
  3351. background: linear-gradient(to right top, #147FBB, #5EB3E3);
  3352. }
  3353. &.bg-linear3 {
  3354. color: #fff;
  3355. font-size: 20px;
  3356. background: linear-gradient(to right bottom, #2F9E8A, #56CDB1);
  3357. }
  3358. &:hover {
  3359. margin-top: -5px;
  3360. box-shadow: 3px 3px 6px #ccc, -3px -3px 6px #ccc;
  3361. }
  3362. .citem-img {
  3363. width: 50px;
  3364. margin-bottom: 10px;
  3365. }
  3366. }
  3367. }
  3368. .popper-open{
  3369. text-align: center !important;
  3370. padding: 10px !important;
  3371. background: #303133 !important;
  3372. color: #fff !important;
  3373. min-width: 120px !important;
  3374. opacity: 0.8;
  3375. }
  3376. .popper-open[x-placement^=bottom] .popper__arrow::after{
  3377. border-bottom-color: #303133 !important;
  3378. }
  3379. textarea.el-textarea__inner{
  3380. height: 100% !important;
  3381. font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
  3382. }
  3383. .set-item{
  3384. margin-right: 15px;
  3385. .set-title{
  3386. font-size: 13px;
  3387. }
  3388. }
  3389. .outarea{
  3390. height: 100%;
  3391. border: 1px solid #DCDFE6;
  3392. background-color: #4851a415;
  3393. padding: 15px;
  3394. font-size: 20px;
  3395. overflow: hidden auto;
  3396. }
  3397. .outtext{
  3398. height: 100%;
  3399. font-size: 20px;
  3400. overflow: hidden auto;
  3401. textarea{
  3402. background-color: #4851a415;
  3403. }
  3404. }
  3405. .pin-tips{
  3406. font-size: 14px;
  3407. position: absolute;
  3408. bottom: 10px;
  3409. color: #ff0000;
  3410. left: 0;
  3411. right: 0;
  3412. margin: auto;
  3413. text-align: center;
  3414. }
  3415. .outarea.red-border{
  3416. border: 1px solid #F56C6C;
  3417. }
  3418. .outtext.red-border textarea{
  3419. border: 1px solid #F56C6C;
  3420. }
  3421. h3{
  3422. margin: 0;
  3423. }
  3424. .m-image{
  3425. width: 20px;
  3426. margin-right: 5px;
  3427. }
  3428. .dialog-footer-center{
  3429. text-align: center;
  3430. }
  3431. .visible-tips-style{
  3432. font-size: 18px;
  3433. color: #f73131;
  3434. font-weight: 600;
  3435. padding: 30px 40px 0;
  3436. }
  3437. .no-select{
  3438. user-select: none;
  3439. }
  3440. .tips-flex{
  3441. display: flex;
  3442. flex-wrap: nowrap;
  3443. justify-content: space-around;
  3444. align-items: center;
  3445. .el-icon-s-opportunity{
  3446. font-size: 50px;
  3447. color: #f73131;
  3448. margin-right: 10px;
  3449. }
  3450. .m-title{
  3451. flex: 1;
  3452. color: #f73131;
  3453. }
  3454. }
  3455. </style>