create_ad_layout.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. from selenium.webdriver.support.wait import WebDriverWait
  2. from selenium.webdriver.common.keys import Keys
  3. from selenium.webdriver import ActionChains
  4. from logging import handlers
  5. import logging
  6. import requests
  7. import random
  8. import shutil
  9. import time
  10. import re
  11. import os
  12. class CreateAd:
  13. def __init__(self, login_ad, service_name, wechat_name):
  14. self.log_ad = login_ad
  15. self.service_name = service_name
  16. self.wechat_name = wechat_name
  17. self.driver = login_ad.get_driver_loged()
  18. self.get_into_create_page()
  19. self.send_file_limit_num = 8
  20. self.img_dir = './img'
  21. def get_into_create_page(self):
  22. # 进入创建页面
  23. self.driver.find_element_by_id('material').click()
  24. try:
  25. # 落地页内容有的账户有,有的无,无的默认等5s
  26. WebDriverWait(self.driver, 5).until(lambda driver: len(self.driver.find_elements_by_xpath(
  27. '//*[@class="adui-table-tr"]')))
  28. print( len(self.driver.find_elements_by_xpath(
  29. '//*[@class="adui-table-tr"]')))
  30. except:
  31. pass
  32. WebDriverWait(self.driver, 10).until(lambda driver: self.driver.find_element_by_xpath(
  33. '//*[@class="ui-fl-r adui-button-base adui-button-primary adui-button-small"]'))
  34. create_element = self.driver.find_element_by_xpath(
  35. '//*[@class="ui-fl-r adui-button-base adui-button-primary adui-button-small"]')
  36. WebDriverWait(self.driver, 10).until(
  37. lambda driver: create_element.is_displayed() and create_element.is_enabled())
  38. # is_displayed 和 is_enabled 没有那么快就可以使用
  39. time.sleep(0.1)
  40. create_element.click()
  41. WebDriverWait(self.driver, 5).until(lambda driver: driver.find_element_by_css_selector(
  42. '#wxadcontainer > div:nth-child(1) > div:nth-child(2) > div.dialog-1fj_N480ZT > div > div > div:nth-child(1) > div.dialogCardFooter-17KpBD1lgN > button'))
  43. self.driver.find_element_by_css_selector(
  44. '#wxadcontainer > div:nth-child(1) > div:nth-child(2) > div.dialog-1fj_N480ZT > div > div > div:nth-child(1) > div.dialogCardFooter-17KpBD1lgN > button').click()
  45. self.driver.switch_to.window(self.driver.window_handles[-1])
  46. WebDriverWait(self.driver, 100).until(lambda driver: driver.find_element_by_class_name('addContent-8pexaaAGYy'))
  47. self.driver.find_element_by_class_name('addContent-8pexaaAGYy').click()
  48. WebDriverWait(self.driver, 100).until(lambda driver: driver.find_element_by_class_name('topArea-qOwEAeNuIn'))
  49. def set_advertisement_sign(self, layout_name):
  50. # 设置广告标记
  51. self.driver.find_element_by_xpath('//*[@class="icon-edQB0KK2VG"]').click()
  52. input_element = self.driver.find_element_by_xpath('//input[@class="input-2lFnByGCRh"]')
  53. input_element.send_keys(Keys.BACKSPACE)
  54. input_element.send_keys(layout_name)
  55. def set_background_color(self, color):
  56. color_buttons = self.driver.find_elements_by_class_name('adui-cp-picker')
  57. c_buttons_can_use = []
  58. for _ in color_buttons:
  59. if _.is_displayed() and _.is_enabled():
  60. c_buttons_can_use.append(_)
  61. c_buttons_can_use[0].click()
  62. time.sleep(random.uniform(0.2, 0.3))
  63. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  64. for _ in input_elements:
  65. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == 'FFFFFF':
  66. _.click()
  67. _.send_keys(color)
  68. def set_head_assemb(self, info):
  69. def single_page_set():
  70. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[1]/div/div').click()
  71. time.sleep(random.uniform(0.1, 0.2))
  72. # 设置图片格式
  73. if info['content']['adSite'] != '朋友圈信息流':
  74. self.driver.find_elements_by_xpath('//*[@class="adui-radio-indicator"]')[1].click()
  75. elif info['content']['outerStyle'] != '常规广告':
  76. select_e = self.driver.find_elements_by_xpath('//*[@class="adui-select-selection-item"]')
  77. for _ in select_e:
  78. if _.text == '常规广告':
  79. _.click()
  80. time.sleep(0.1)
  81. select_e = self.driver.find_elements_by_xpath('//*[@class="adui-select-item-option-content"]')
  82. for _ in select_e:
  83. if _.text == '卡片广告':
  84. _.click()
  85. # 上传图片
  86. file_name = re.split('\/', info['content']['url'])[-1]
  87. self.driver.find_element_by_class_name('upload-img-item-inner-2gsg7NjaZ8').click()
  88. WebDriverWait(self.driver, 10).until(
  89. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  90. _.is_displayed() and _.is_enabled()]) > 0)
  91. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  92. can_use_button = []
  93. for _ in turn_page_buttons:
  94. if _.is_enabled() and _.is_displayed():
  95. can_use_button.append(_)
  96. # 不断翻页获取到元素为止
  97. chose_over = False
  98. while True:
  99. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  100. for _ in page_elements:
  101. if _.is_displayed() and _.is_enabled():
  102. if file_name in _.text:
  103. _.click()
  104. chose_over = True
  105. break
  106. if chose_over or len(can_use_button) == 0:
  107. break
  108. # 翻到最后一页时停止
  109. page_text = self.driver.find_element_by_class_name('count_small-37CcvfzoTl').text
  110. page_nums = re.findall('\d+', page_text)
  111. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  112. break
  113. # 翻页
  114. can_use_button[2].click()
  115. # 确保翻页成功
  116. WebDriverWait(self.driver, 10).until(
  117. lambda x: page_text != self.driver.find_element_by_class_name('count_small-37CcvfzoTl').text)
  118. self.driver.find_element_by_xpath('//*[@id="test_material_container_confirm"]').click()
  119. try:
  120. WebDriverWait(self.driver, 4).until(
  121. lambda driver: driver.find_element_by_class_name(
  122. 'btnFist-uueBS6DQFa'))
  123. _ = self.driver.find_element_by_class_name(
  124. 'btnFist-uueBS6DQFa')
  125. WebDriverWait(self.driver, 4).until(
  126. lambda x: (_.is_displayed() and _.is_enabled()))
  127. time.sleep(1)
  128. _.click()
  129. WebDriverWait(self.driver, 100).until(
  130. lambda driver: driver.find_element_by_class_name(
  131. 'btn-3E823IXt3m'))
  132. _ = self.driver.find_element_by_class_name(
  133. 'btn-3E823IXt3m')
  134. WebDriverWait(self.driver, 100).until(
  135. lambda x: (_.is_displayed() and _.is_enabled()))
  136. time.sleep(1)
  137. _.click()
  138. except Exception as e:
  139. pass
  140. logging.info('头版首页单图上传结束')
  141. def multi_page_set():
  142. # TODO:现在图片设置为素材库,需要对应下载然后存储
  143. self.driver.find_element_by_css_selector(
  144. '#stage-sidebar > div.topArea-qOwEAeNuIn > div > div:nth-child(2)').click()
  145. time.sleep(random.uniform(0.1, 0.2))
  146. page_size = len(info_v)
  147. if page_size == 3:
  148. pass
  149. if page_size == 4:
  150. self.driver.find_element_by_css_selector(
  151. '#stage-settings > div:nth-child(1) > div > div > div:nth-child(3) > div.adui-form-item > div.adui-form-control > div > button:nth-child(2)').click()
  152. if page_size == 6:
  153. self.driver.find_element_by_css_selector(
  154. '#stage-settings > div:nth-child(1) > div > div > div:nth-child(3) > div.adui-form-item > div.adui-form-control > div > button:nth-child(3)').click()
  155. time.sleep(random.uniform(0.1, 0.2))
  156. self.driver.find_element_by_class_name('imageUploadItem-tA9JX0RWua').click()
  157. WebDriverWait(self.driver, 1000).until(
  158. lambda driver: self.driver.find_element_by_class_name('adui-tabs-tab')
  159. )
  160. input_elements = self.driver.find_elements_by_tag_name('input')
  161. input_find_element = None
  162. for _ in input_elements:
  163. if '输入关键词搜索素材' in _.get_attribute('placeholder'):
  164. input_find_element = _
  165. for _ in info_v:
  166. file_name = os.path.basename(_)
  167. logging.info(file_name)
  168. input_find_element.send_keys(file_name)
  169. input_find_element.send_keys(Keys.RETURN)
  170. WebDriverWait(self.driver, 1000).until(
  171. lambda driver: driver.find_element_by_class_name('img-2HvhMmpnzP'))
  172. file_element = self.driver.find_element_by_class_name('img-2HvhMmpnzP')
  173. WebDriverWait(self.driver, 1000).until(
  174. lambda x: (file_element.is_displayed() and file_element.is_enabled()))
  175. ActionChains(self.driver).move_to_element(file_element).perform()
  176. time.sleep(random.uniform(0.5, 1))
  177. file_element.click()
  178. for i in range(len(file_name) + 10):
  179. input_find_element.send_keys(Keys.BACKSPACE)
  180. time.sleep(random.uniform(0.5, 1))
  181. self.driver.find_element_by_xpath('/html/body/div[12]/div/div/div[2]/div/div[3]/button[2]').click()
  182. # 切图操作如果有的话进行对应操作.
  183. for i in range(len(info_v) + 1):
  184. try:
  185. WebDriverWait(self.driver, 6).until(
  186. lambda driver: driver.find_element_by_xpath(
  187. '/html/body/div[13]/div/div/div[2]/div/div[3]/button[2]'))
  188. self.driver.find_element_by_xpath('/html/body/div[13]/div/div/div[2]/div/div[3]/button[2]').click()
  189. except:
  190. pass
  191. logging.info('头版多图选择 结束')
  192. def movie_set():
  193. # TODO:视频转为链接,
  194. file_name = os.path.basename(info_v)
  195. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[3]/div/div').click()
  196. self.driver.find_element_by_xpath('//*[@class="comptEditButton-2JsnAFdOGZ"]').click()
  197. WebDriverWait(self.driver, 100).until(
  198. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  199. _.is_displayed() and _.is_enabled()]) > 0)
  200. #
  201. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  202. can_use_button = []
  203. for _ in turn_page_buttons:
  204. if _.is_enabled() and _.is_displayed():
  205. can_use_button.append(_)
  206. # 不断翻页获取到元素为止
  207. chose_over = False
  208. while True:
  209. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  210. for _ in page_elements:
  211. if _.is_displayed() and _.is_enabled():
  212. if file_name in _.text:
  213. _.click()
  214. chose_over = True
  215. break
  216. if chose_over or len(can_use_button) == 0:
  217. # can_use_button 数量说明是否可以翻页,如果不可以翻页,则直接停止
  218. break
  219. # 翻到最后一页时停止
  220. page_text_elements = self.driver.find_elements_by_class_name('count_small-37CcvfzoTl')
  221. for _ in page_text_elements:
  222. if _.is_enabled() and _.is_displayed():
  223. page_text = _.text
  224. page_text_element = _
  225. page_nums = re.findall('\d+', page_text)
  226. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  227. break
  228. # 翻页
  229. can_use_button[2].click()
  230. # 确保翻页成功
  231. WebDriverWait(self.driver, 10).until(
  232. lambda x: page_text != page_text_element.text)
  233. sc_buttons = self.driver.find_elements_by_id('test_material_container_confirm')
  234. for _ in sc_buttons:
  235. if _.is_enabled() and _.is_displayed():
  236. _.click()
  237. info_type = info['type']
  238. info_v = None # TODO: 暂时存在,之后修改好multi_page_set 和movie_set.就删除
  239. if info['type'] == 'topImg':
  240. single_page_set()
  241. if info['type'] == 'topSlider':
  242. multi_page_set()
  243. if info['type'] == 'topVideo':
  244. movie_set()
  245. # 设置头部组件
  246. pass
  247. def set_page(self, config_info):
  248. page_link = config_info['url']
  249. # 设置图片模块
  250. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[2]/div[1]/div/div').click()
  251. time.sleep(random.uniform(0.1, 0.2))
  252. file_name = re.split('\/', page_link)[-1]
  253. upload_elements = self.driver.find_elements_by_class_name('upload-img-item-inner-2gsg7NjaZ8')
  254. for _ in upload_elements:
  255. if _.is_displayed() and _.is_enabled():
  256. _.click()
  257. WebDriverWait(self.driver, 10).until(
  258. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  259. _.is_displayed() and _.is_enabled()]) > 0)
  260. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  261. can_use_button = []
  262. for _ in turn_page_buttons:
  263. if _.is_enabled() and _.is_displayed():
  264. can_use_button.append(_)
  265. # 不断翻页获取到元素为止
  266. chose_over = False
  267. while True:
  268. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  269. for _ in page_elements:
  270. if _.is_displayed() and _.is_enabled():
  271. if file_name in _.text:
  272. _.click()
  273. chose_over = True
  274. break
  275. if chose_over or len(can_use_button) == 0:
  276. # can_use_button 数量说明是否可以翻页,如果不可以翻页,则直接停止
  277. break
  278. # 翻到最后一页时停止
  279. page_text_elements = self.driver.find_elements_by_class_name('count_small-37CcvfzoTl')
  280. for _ in page_text_elements:
  281. if _.is_enabled() and _.is_displayed():
  282. page_text = _.text
  283. page_text_element = _
  284. page_nums = re.findall('\d+', page_text)
  285. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  286. break
  287. # 翻页
  288. can_use_button[2].click()
  289. # 确保翻页成功
  290. WebDriverWait(self.driver, 10).until(
  291. lambda x: page_text != page_text_element.text)
  292. sc_buttons = self.driver.find_elements_by_id('test_material_container_confirm')
  293. for _ in sc_buttons:
  294. if _.is_enabled() and _.is_displayed():
  295. _.click()
  296. try:
  297. WebDriverWait(self.driver, 4).until(
  298. lambda driver: driver.find_element_by_class_name(
  299. 'btnFist-uueBS6DQFa'))
  300. _ = self.driver.find_element_by_class_name(
  301. 'btnFist-uueBS6DQFa')
  302. WebDriverWait(self.driver, 4).until(
  303. lambda x: (_.is_displayed() and _.is_enabled()))
  304. # 已经出现但任需要等待
  305. time.sleep(1)
  306. _.click()
  307. WebDriverWait(self.driver, 100).until(
  308. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('btn-3E823IXt3m') if
  309. _.is_displayed() and _.is_enabled()]) > 0)
  310. for _ in self.driver.find_elements_by_class_name('btn-3E823IXt3m'):
  311. if _.is_displayed() and _.is_enabled():
  312. _.click()
  313. except Exception as e:
  314. logging.info(e)
  315. # 设置文本边距
  316. if config_info['marginTop'] != 0 or config_info['marginBottom'] != 0:
  317. distance_buttons = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  318. distance_buttons_can_use = []
  319. for _ in distance_buttons:
  320. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '0':
  321. distance_buttons_can_use.append(_)
  322. distance_buttons_can_use[0].click()
  323. for i in range(4):
  324. distance_buttons_can_use[0].send_keys(Keys.BACKSPACE)
  325. distance_buttons_can_use[0].send_keys(config_info['marginTop'])
  326. distance_buttons_can_use[1].click()
  327. for i in range(4):
  328. distance_buttons_can_use[1].send_keys(Keys.BACKSPACE)
  329. distance_buttons_can_use[1].send_keys(config_info['marginBottom'])
  330. logging.info('图片模块设置结束')
  331. def set_content(self, config_info):
  332. # TODO:长文本需要优化输入时间
  333. logging.info(' 开始设置文本模块')
  334. # 设置文本模块
  335. # 1.文本内容2.文本颜色3.是否加粗4.文本位置设置5.文本大小
  336. # 设置文本内容
  337. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[2]/div[5]/div/div').click()
  338. time.sleep(random.uniform(0.2, 0.3))
  339. input_elements = self.driver.find_elements_by_xpath('//textarea[@class="adui-input-base"]')
  340. for _ in input_elements:
  341. if _.is_enabled() and _.is_displayed():
  342. _.send_keys(config_info['text'])
  343. # 设置颜色
  344. if config_info['color'] != '#595959':
  345. color_buttons = self.driver.find_elements_by_class_name('adui-cp-picker')
  346. c_buttons_can_use = []
  347. for _ in color_buttons:
  348. if _.is_displayed() and _.is_enabled():
  349. c_buttons_can_use.append(_)
  350. c_buttons_can_use[1].click()
  351. time.sleep(random.uniform(0.2, 0.3))
  352. input_elements = self.driver.find_elements_by_tag_name('input')
  353. for _ in input_elements:
  354. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '595959':
  355. _.click()
  356. _.send_keys(config_info['color'])
  357. # 设置是否加粗
  358. if config_info['fontWeight'] != 'normal':
  359. big_elements = self.driver.find_elements_by_class_name('adui-button-content')
  360. for _ in big_elements:
  361. if _.text == '加粗' and _.is_displayed() and _.is_enabled():
  362. _.click()
  363. # 设置文本位置
  364. if config_info['textAlign'] != 'left':
  365. loc_buttons = self.driver.find_elements_by_xpath(
  366. "//div[contains(@class, 'adui-button-group_banner')]//button")
  367. loc_buttons_can_use = []
  368. for _ in loc_buttons:
  369. if _.is_enabled() and _.is_displayed():
  370. loc_buttons_can_use.append(_)
  371. if config_info['textAlign'] == 'center':
  372. loc_buttons_can_use[1].click()
  373. if config_info['textAlign'] == 'right':
  374. loc_buttons_can_use[2].click()
  375. # 设置文本大小
  376. if config_info['fontSize'] != 15:
  377. str_buttons = self.driver.find_elements_by_xpath("//*[@class='adui-select-selection-search']")
  378. str_buttons_can_use = []
  379. for _ in str_buttons:
  380. if _.is_displayed() and _.is_enabled():
  381. str_buttons_can_use.append(_)
  382. str_buttons_can_use[1].click()
  383. time.sleep(random.uniform(0.5, 1))
  384. str_num_buttons = self.driver.find_elements_by_xpath("//*[@class='adui-select-item-option-content']")
  385. str_num_can_use = []
  386. for _ in str_num_buttons:
  387. if _.is_displayed() and _.is_enabled():
  388. str_num_can_use.append(_)
  389. # str_num_map = {14: 0, 15: 1, 16: 2, 18: 3, 20: 4, 24: 5, 36: 6}
  390. # str_num_can_use[str_num_map[config_info['fontSize']]].click()
  391. for _ in str_num_can_use:
  392. if _.text == str(config_info['fontSize']):
  393. _.click()
  394. # 设置文本边距
  395. if config_info['marginTop'] != 22 or config_info['marginBottom'] != 22:
  396. distance_buttons = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  397. distance_buttons_can_use = []
  398. for _ in distance_buttons:
  399. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '22':
  400. distance_buttons_can_use.append(_)
  401. distance_buttons_can_use[0].click()
  402. for i in range(4):
  403. distance_buttons_can_use[0].send_keys(Keys.BACKSPACE)
  404. distance_buttons_can_use[0].send_keys(config_info['marginTop'])
  405. distance_buttons_can_use[1].click()
  406. for i in range(4):
  407. distance_buttons_can_use[1].send_keys(Keys.BACKSPACE)
  408. distance_buttons_can_use[1].send_keys(config_info['marginBottom'])
  409. def set_follow_button(self, config_info):
  410. # TODO:是否一键关注
  411. # 设置关注按钮
  412. # 0.是否一键关注 1.设置button文本内容 2.是否加粗 3.设置字体颜色,边框颜色,填充色 4.设置边距
  413. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[4]/div[2]/div/div').click()
  414. # 开始设置一键关注
  415. if 'follow' in config_info.keys():
  416. if not config_info['follow']:
  417. time.sleep(0.1)
  418. follow_bs = self.driver.find_elements_by_xpath(
  419. '//*[@class="form-caption-3Xp3o6Drwf"]/div/span')
  420. for _ in follow_bs:
  421. if _.is_displayed() and _.is_enabled():
  422. _.click()
  423. # 文本设置
  424. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  425. for _ in input_elements:
  426. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '关注公众号':
  427. _.click()
  428. _.clear()
  429. for i in range(10):
  430. _.send_keys(Keys.BACKSPACE)
  431. _.send_keys(config_info['text'])
  432. # 文本是否加粗
  433. if config_info['fontWeight'] != 'normal':
  434. big_elements = self.driver.find_elements_by_xpath('//span[@class="adui-button-content"]')
  435. for _ in big_elements:
  436. if _.text == '加粗' and _.is_displayed() and _.is_enabled():
  437. _.click()
  438. # 颜色设置
  439. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  440. input_elements_can_use = []
  441. for _ in input_elements:
  442. if _.is_enabled() and _.is_displayed() and (
  443. _.get_attribute("value") == '07C160' or _.get_attribute("value") == 'FFFFFF'):
  444. input_elements_can_use.append(_)
  445. if config_info['textColor'] != '#FFFFFF':
  446. input_elements_can_use[0].click()
  447. input_elements_can_use[0].send_keys(config_info['textColor'])
  448. time.sleep(random.uniform(0.1, 0.5))
  449. if config_info['borderColor'] != '#FFFFFF':
  450. input_elements_can_use[1].click()
  451. input_elements_can_use[1].send_keys(config_info['borderColor'])
  452. time.sleep(random.uniform(0.1, 0.5))
  453. input_elements_can_use[2].click()
  454. input_elements_can_use[2].send_keys(config_info['backColor'])
  455. time.sleep(random.uniform(0.1, 0.5))
  456. # 间隙设置
  457. size_buttons = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  458. size_buttons_can_use = []
  459. for _ in size_buttons:
  460. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '28':
  461. size_buttons_can_use.append(_)
  462. size_buttons_can_use[0].click()
  463. for i in range(4):
  464. size_buttons_can_use[0].send_keys(Keys.BACKSPACE)
  465. size_buttons_can_use[0].send_keys(config_info['marginTop'])
  466. size_buttons_can_use[1].click()
  467. for i in range(4):
  468. size_buttons_can_use[1].send_keys(Keys.BACKSPACE)
  469. size_buttons_can_use[1].send_keys(config_info['marginBottom'])
  470. def set_text_button(self):
  471. # 设置图文按钮
  472. pass
  473. def send_file_multi(self, layout, err_num=0):
  474. # 有问题,暂时不使用
  475. # 上传文件,文件上传与整体流程切割开
  476. token = re.findall('token=(\d+)', self.driver.current_url)
  477. url_ = 'https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=material_std/material_library&token={}'.format(
  478. token[0])
  479. js = "window.open('{}')".format(url_)
  480. self.driver.execute_script(js)
  481. time.sleep(random.uniform(1, 2))
  482. self.driver.switch_to.window(self.driver.window_handles[-1])
  483. file_set = set()
  484. for v in layout.values():
  485. if isinstance(v, dict):
  486. if 'multi_page' in v.keys() or 'page' in v.keys() or 'movie' in v.keys():
  487. v_name = list(v.keys())[0]
  488. if isinstance(v[v_name], list):
  489. for _ in v[v_name]:
  490. file_set.add(_)
  491. else:
  492. file_set.add(v[v_name])
  493. file_list = list(file_set)
  494. # print(file_list)
  495. # print('file list size', len(file_list))
  496. send_file_sign = self.send_file_limit_num
  497. for _ in file_list:
  498. # print(_)
  499. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(_)
  500. time.sleep(100)
  501. while True:
  502. # 失败,失败直接退出重跑
  503. # 正在上传数量,如果是正在上传小于限定数量,就不断输入
  504. # 上传完毕,小于限定数量,不断输入,.....已经上传好了,就关闭
  505. time.sleep(1)
  506. send_reslut_content = self.driver.find_element_by_xpath(
  507. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/div/strong').text
  508. if '失败' in send_reslut_content:
  509. if err_num < 3:
  510. self.send_file(layout, err_num=err_num + 1)
  511. else:
  512. exit()
  513. if '正在上传' in send_reslut_content:
  514. if send_file_sign < len(file_list):
  515. send_num = re.findall('(\d+)', send_reslut_content)[0]
  516. if int(send_num) < self.send_file_limit_num:
  517. # 还可以继续上传
  518. x = send_file_sign
  519. can_send_sign = send_file_sign + (self.send_file_limit_num - send_num)
  520. y = can_send_sign if can_send_sign < len(file_list) else len(file_list)
  521. for i in range(x, y):
  522. send_file_sign = send_file_sign + 1
  523. self.driver.find_element_by_xpath(
  524. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_list[i])
  525. else:
  526. pass
  527. if '上传成功' in send_reslut_content:
  528. if send_file_sign < len(file_list):
  529. send_num = re.findall('(\d+)', send_reslut_content)[0]
  530. if int(send_num) < self.send_file_limit_num:
  531. # 还可以继续上传
  532. x = send_file_sign
  533. can_send_sign = send_file_sign + (self.send_file_limit_num - send_num)
  534. y = can_send_sign if can_send_sign < len(file_list) else len(file_list)
  535. for i in range(x, y):
  536. send_file_sign = send_file_sign + 1
  537. self.driver.find_element_by_xpath(
  538. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_list[i])
  539. else:
  540. break
  541. time.sleep(1000)
  542. self.driver.execute_script('window.close();')
  543. def send_file(self, file_link, err_num=0):
  544. # 下载图片,存储于
  545. if not os.path.exists(self.img_dir):
  546. os.makedirs(self.img_dir)
  547. link_pra = re.split('\/', file_link)
  548. file_path = os.getcwd() + '/' + self.img_dir + '/' + link_pra[-1]
  549. rsp = requests.get(file_link)
  550. with open(file_path, 'wb') as f:
  551. f.write(rsp.content)
  552. # 有问题,暂时不使用
  553. self.driver.execute_script('location.reload();')
  554. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_path)
  555. def send_file_alone(self, layout):
  556. def get_url(v_info):
  557. if 'url' in v_info.keys():
  558. file_set.add(v_info['url'])
  559. for v in v_info.values():
  560. if isinstance(v, dict):
  561. get_url(v)
  562. if isinstance(v, list):
  563. for _ in v:
  564. if isinstance(_, dict):
  565. get_url(_)
  566. # 上传文件,单线程
  567. # 上传文件,文件上传与整体流程切割开
  568. WebDriverWait(self.driver, 10).until(
  569. lambda x: len(re.findall('token=(\d+)', self.driver.current_url)))
  570. token = re.findall('token=(\d+)', self.driver.current_url)
  571. url_ = 'https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=material_std/material_library&token={}'.format(
  572. token[0])
  573. js = "window.open('{}')".format(url_)
  574. self.driver.execute_script(js)
  575. time.sleep(random.uniform(1, 2))
  576. self.driver.switch_to.window(self.driver.window_handles[-1])
  577. file_set = set()
  578. # TODO:之后还有multi_page 和 movie
  579. # for v in layout.values():
  580. # if isinstance(v, dict):
  581. # if 'multi_page' in v.keys() or 'page' in v.keys() or 'movie' in v.keys():
  582. # v_name = list(v.keys())[0]
  583. # if isinstance(v[v_name], list):
  584. # for _ in v[v_name]:
  585. # file_set.add(_)
  586. # else:
  587. # file_set.add(v[v_name])
  588. get_url(layout)
  589. for _ in file_set:
  590. self.send_file(_)
  591. err_num = 0
  592. while True:
  593. time.sleep(1)
  594. send_reslut_content = self.driver.find_element_by_xpath(
  595. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/div/strong').text
  596. if '上传成功' in send_reslut_content:
  597. break
  598. if '失败' in send_reslut_content:
  599. err_num = err_num + 1
  600. self.send_file(_)
  601. if err_num > 3:
  602. raise ValueError("图片上传失败")
  603. self.driver.execute_script('window.close();')
  604. self.driver.switch_to.window(self.driver.window_handles[-1])
  605. def set_share_content(self, title_content, des_content):
  606. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div/section/header/div[2]/button[2]').click()
  607. WebDriverWait(self.driver, 50).until(lambda driver: driver.find_element_by_xpath(
  608. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[1]/div/div/input'))
  609. title_input = self.driver.find_element_by_xpath(
  610. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[1]/div/div/input')
  611. title_input.click()
  612. title_input.send_keys(title_content)
  613. des_input = self.driver.find_element_by_xpath(
  614. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[2]/div/div/input')
  615. des_input.click()
  616. des_input.send_keys(des_content)
  617. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div/header/div[2]/button').click()
  618. WebDriverWait(self.driver, 10).until(
  619. lambda driver: driver.find_element_by_xpath('/html/body/div[6]/div/div/div[2]/div/div[3]/button[2]'))
  620. self.driver.find_element_by_xpath('/html/body/div[6]/div/div/div[2]/div/div[3]/button[2]').click()
  621. time.sleep(1)
  622. @staticmethod
  623. def check_sucess_api(log_ad, layout_name):
  624. # 默认在进入公众号初始页面
  625. logging.info('开始检查落地页是否创建成功')
  626. WebDriverWait(log_ad.driver, 100).until(
  627. lambda driver: True if 'token' in log_ad.driver.current_url else False)
  628. cookie_dict = log_ad.get_cookie(log_ad.driver, login_cookie=False)
  629. token_id = re.findall('token=(\d+)', log_ad.driver.current_url)[0]
  630. requests.session()
  631. layout_url = 'https://mp.weixin.qq.com/promotion/landingpage_manager?action=list_pages&page=1&page_size=10&canvas_name={layout_name}&login_from=&is_grant=0&owner_uid=&token={wechat_token}&appid=&spid=&_={time_}'.format(
  632. layout_name=layout_name, wechat_token=token_id, time_=int(time.time() * 1000))
  633. session = requests.session()
  634. rsp = session.get(url=layout_url, cookies=cookie_dict)
  635. result_json = rsp.json()
  636. if 'landing_page_list' in result_json.keys():
  637. if len(result_json['landing_page_list']):
  638. logging.info('对应落地页存在于微信后台')
  639. return True
  640. def remove_all_file(self):
  641. shutil.rmtree(os.getcwd() + '/' + self.img_dir)
  642. pass
  643. def create_layout(self, layout, err_num=0):
  644. #
  645. try:
  646. self.send_file_alone(layout)
  647. self.set_advertisement_sign(layout_name=layout['layoutName'])
  648. self.set_head_assemb(layout['topContent'])
  649. self.set_background_color(layout['pageBackColor'])
  650. for _ in layout['content']:
  651. if _['type'] == 'img':
  652. self.set_page(_['content'])
  653. if _['type'] == 'txt':
  654. self.set_content(_['content'])
  655. if _['type'] == 'followAcc':
  656. self.set_follow_button(_['content'])
  657. self.set_share_content(title_content=layout['shareTittle'], des_content=layout['shareDesc'])
  658. self.remove_all_file()
  659. if self.check_sucess_api(layout_name=layout['layoutName'], log_ad=self.log_ad):
  660. return {'sucess': True, 'result_info': ''}
  661. else:
  662. if err_num > 3:
  663. return {'sucess': False, 'result_info': '过程中全程无错误,失败'}
  664. else:
  665. self.log_ad.refresh_driver()
  666. self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
  667. self.get_into_create_page()
  668. return self.create_layout(layout, err_num=err_num + 1)
  669. except Exception as e:
  670. raise
  671. logging.error(e)
  672. # TODO:有空时讲 e 内容设置为原始内容
  673. if err_num > 3:
  674. return {'sucess': False, 'result_info': str(e)}
  675. else:
  676. self.log_ad.refresh_driver()
  677. self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
  678. self.get_into_create_page()
  679. return self.create_layout(layout, err_num=err_num + 1)
  680. if __name__ == '__main__':
  681. logging.basicConfig(
  682. handlers=[
  683. logging.handlers.RotatingFileHandler('./create_ad_layout.log',
  684. maxBytes=10 * 1024 * 1024,
  685. backupCount=5,
  686. encoding='utf-8')
  687. , logging.StreamHandler() # 供输出使用
  688. ],
  689. level=logging.INFO,
  690. format="%(asctime)s - %(levelname)s %(filename)s %(funcName)s %(lineno)s - %(message)s"
  691. )