当前位置:   article > 正文

selenium小练习:自写利用 selenium 下载Google高清图片、大众点评自动传头像/评论_selenium下载图片

selenium下载图片

一、 selenium 下载高清图片

1、版本介绍

  1. python 3.7.4
  2. selenium = 3.141.0
  3. chromedriver=84.0.4147.30

2、保存 base64 图片格式代码

  1. src="data:image/gif;base64,R0lGODlhMwAxAIAAAAAAAPyH5BAAAAAAALAAAAAAzADEAAAK8jI+pBr0PowytzotTtbm/DTqQ6C3hGX
  2. ElcraA9jIr66ozVpM3nseUvYP1UEHF0FUUHkNJxhLZfEJNvol06tzwrgd
  3. LbXsFZYmSMPnHLB+zNJFbq15+SOf50+6rG7lKOjwV1ibGdhHYRVYVJ9Wn
  4. k2HWtLdIWMSH9lfyODZoZTb4xdnpxQSEF9oyOWIqp6gaI9pI1Qo7BijbF
  5. ZkoaAtEeiiLeKn72xM7vMZofJy8zJys2UxsCT3kO229LH1tXAAAOw=="

     提取出其中的base64地址(即 base64, 后的内容)然后base64解码,然后保存为图片

  1. url='''R0lGODlhMwAxAIAAAAAAAPyH5BAAAAAAALAAAAAAzADEAAAK8jI+pBr0PowytzotTtbm/DTqQ6C3hGX
  2. ElcraA9jIr66ozVpM3nseUvYP1UEHF0FUUHkNJxhLZfEJNvol06tzwrgd
  3. LbXsFZYmSMPnHLB+zNJFbq15+SOf50+6rG7lKOjwV1ibGdhHYRVYVJ9Wn
  4. k2HWtLdIWMSH9lfyODZoZTb4xdnpxQSEF9oyOWIqp6gaI9pI1Qo7BijbF
  5. ZkoaAtEeiiLeKn72xM7vMZofJy8zJys2UxsCT3kO229LH1tXAAAOw=='''
  6. import base64
  7. img=base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
  8. fh = open("imageToSave.png", "wb")
  9. fh.write(img)
  10. fh.close()
'
运行

3、selenium 对某个元素截图保存 .screenshot()方法

由于Google网络的原因,一些外网的图片高清图加载失败,导致下载的是缩减图,这一部分数据通过截取详情图片的元素来解决。
  1. from selenium import webdriver
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. from selenium.webdriver.support import expected_conditions as EC
  5. import time
  6. import os
  7. import re
  8. import requests
  9. import urllib3
  10. urllib3.disable_warnings() # 去除警告
  11. options = webdriver.ChromeOptions()
  12. # 增加无头
  13. options.add_argument('--disable-gpu')
  14. # 防止被网站识别,开发者模式
  15. options.add_experimental_option('excludeSwitches', ['enable-automation'])
  16. browser = webdriver.Chrome(options=options)
  17. browser.maximize_window()
  18. browser.implicitly_wait(10)
  19. browser.get('https://www.google.com/search?q=%E6%BF%80%E5%87%B8&tbm=isch&hl=zh-CN&hl=zh-CN#imgrc=1lpdzdDLl6rN9M')
  20. ele = browser.find_element_by_xpath('//*[@id="Sva75c"]/div/div/div[3]/div[2]/c-wiz/div[1]/div[1]/div/div[2]/a/img')
  21. print(ele.get_attribute('src'))
  22. # 截图保存
  23. ele.screenshot('1.png')

4 、selenium 常常遇见的反爬虫几个策略

         主要参考:

                         Selenium反反爬-滑块验证

                         Selenium 系列篇(六):反反爬篇

                         使用 mitmproxy + python 做拦截代理

                         如何突破网站对selenium的屏蔽

                         Selenium-webdriver绕开反爬虫机制的4种方法

                         网站对Selenium的屏蔽

                         

5、爬高清图片的代码

缺点:慢,效果受网络的影响,现在没有更好的方案...
  1. 2个代码都未解决的问题:
  2. ① 使用 无头 浏览器在 ‘点击更多’ 的点击事件可能不能触发
  3. ② 使用 无头 浏览器在 缩减图片截图时有的图片截的图可能有点问题
  4. 希望有知道怎么回事或者怎么解决的老铁请留个言,感谢!

    (1)高清、缩减、base64 格式图片

  1. from selenium import webdriver
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. from selenium.webdriver.support import expected_conditions as EC
  5. from selenium.common.exceptions import ElementNotInteractableException
  6. from selenium.webdriver.common.keys import Keys
  7. from requests.adapters import HTTPAdapter
  8. import argparse
  9. import time
  10. import os
  11. import re
  12. import requests
  13. import urllib3
  14. urllib3.disable_warnings() # 去除警告
  15. class GoogleSpider():
  16. def __init__(self, url, keyword, time_sleep, target_dir):
  17. self.url = url
  18. self.keyword = keyword
  19. self.time_sleep = time_sleep # 等待高清图片加载的时间
  20. self.target_dir = target_dir
  21. self.img_tmp_dir = os.path.join(self.target_dir,
  22. self.add_timestamp(self.keyword))
  23. if not os.path.exists(self.img_tmp_dir):
  24. os.makedirs(self.img_tmp_dir)
  25. self.head = None # 浏览器是否存在头
  26. self.implicitly_wait_time = 5 # 隐形等待时间
  27. self.js_slide_wait = 30 # js 滑动窗口等待时间
  28. def clean_str(self, str_):
  29. """
  30. 清除字符串为图片命名时不合规的字符
  31. :return:
  32. """
  33. str_ = re.sub('[^\u4e00-\u9fa5A-Za-z\d]', '', str_)
  34. return str_
  35. def add_timestamp(self, str_):
  36. """
  37. 为字符串添加时间搓,保证字符串唯一不重复性
  38. :param str_: str
  39. :return:
  40. """
  41. assert isinstance(str_, str)
  42. time_str = str(time.time()).replace('.', '')
  43. str_ = str_ + time_str
  44. return str_
  45. def create_browser(self,head):
  46. """
  47. 创建一个浏览器的对象
  48. :param headless: 是否使用无头浏览器
  49. :return:
  50. """
  51. self.head = head
  52. options = webdriver.ChromeOptions()
  53. # 增加无头
  54. if not self.head:
  55. options.add_argument('--headless')
  56. # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
  57. options.add_argument("--window-size=4000,1600")
  58. options.add_argument('--disable-gpu')
  59. # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
  60. # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
  61. options.add_experimental_option("excludeSwitches", ['enable-automation'])
  62. # 关闭开发者模式
  63. options.add_experimental_option("useAutomationExtension", False)
  64. # 设置中文
  65. options.add_argument('lang=zh_CN.UTF-8')
  66. # 更换头部
  67. options.add_argument(
  68. 'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
  69. # 部署项目在linux时,其驱动会要求这个参数
  70. options.add_argument('--no-sandbox')
  71. browser = webdriver.Chrome(options=options)
  72. if self.head:
  73. browser.maximize_window()
  74. # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
  75. browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  76. "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
  77. })
  78. return browser
  79. def get_main_page_info(self, browser):
  80. """
  81. 获取主页面且拉至最底部,且获取所有图片详情页的链接地址
  82. :return:
  83. """
  84. browser.get(self.url)
  85. browser.implicitly_wait(self.implicitly_wait_time)
  86. # TODO 滑动到底的js代码
  87. js = """
  88. (function () {
  89. var y = document.documentElement.scrollTop;
  90. var step = 100;
  91. window.scroll(0, y);
  92. function f() {
  93. if (y < document.body.scrollHeight) {
  94. y += step;
  95. window.scroll(0, y);
  96. setTimeout(f, 100); //每两次间隔滑动的时间 100ms
  97. }
  98. else {
  99. window.scroll(0, y);
  100. document.title += "scroll-done";
  101. }
  102. }
  103. setTimeout(f, 1000); // 执行函数等待时间 1000ms
  104. })();
  105. """
  106. # TODO 执行滑动到底的操作
  107. browser.execute_script(js)
  108. # 等待窗口滑动结束
  109. for i in range(self.js_slide_wait):
  110. print('\rJS窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
  111. time.sleep(1)
  112. print()
  113. # TODO 点击 ‘ 加载更多的选项 ’
  114. try:
  115. browser.find_element_by_xpath(
  116. '//div[@id="islmp"]/.//div[@jsname="i3y3Ic"]/.//input[@class="mye4qd"]').send_keys(Keys.ENTER)
  117. print('缓冲中...')
  118. time.sleep(8) # ‘加载更多’ 缓冲
  119. # TODO 执行点击加载更多继续滚动
  120. browser.execute_script(js)
  121. # 等待窗口滑动结束
  122. for i in range(self.js_slide_wait):
  123. print('\rJS加载更多图片窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
  124. time.sleep(1)
  125. print()
  126. except Exception as e:
  127. print(e, '网络不畅 或 该网页没有更多内容选项 .... ')
  128. # 获取图片详情页链接地址
  129. div_infos = browser.find_elements_by_xpath(
  130. "//div[@id='islmp']/.//div[contains(@class,'isv-r PNCib MSM1fd')]") # 结果是一个列表
  131. self.reduceImg_num = len(div_infos)
  132. if self.reduceImg_num == 0:
  133. assert Exception('网络链接 {} 错误\n 获取主页面class属性已更改'.format(self.url))
  134. print('一共获取到 {} 张缩减图'.format(self.reduceImg_num))
  135. # 定义重复请求的链接列表,保存 【{url,img_name},...】二元组列表
  136. self.repeat_urls = []
  137. # TODO 通过缩减图 DIV 获取高清图片的地址
  138. for idx, i in enumerate(div_infos):
  139. try:
  140. data_id = i.get_attribute('data-id')
  141. except Exception as e:
  142. logger.error(e)
  143. logger.error('"data_id" 的属性值获取失败,可能网站已更改属性')
  144. continue
  145. # 图片详情页的 url 地址
  146. img_url = self.url + '#imgrc=' + data_id
  147. try:
  148. browser.get(img_url)
  149. self.target_img_url = browser.find_element_by_xpath(
  150. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  151. 'src')
  152. self.target_img_name = browser.find_element_by_xpath(
  153. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  154. 'alt')
  155. # 如果获取的url不以 data: 或者 http 开头,视为获取失败
  156. if not (self.target_img_url.startswith('data:') or self.target_img_url.startswith('http')):
  157. logger.info("第 {} 高清图片url: {} 格式错误,跳过".format(idx + 1, self.target_img_url))
  158. continue
  159. # 对是否详情页加载为高清图的url进行判断: https://encrypted-tbn0.gstatic.com/images? 开头属于缩减图
  160. # 因此对详情页进行最长为 time_sleep 时间的等待,每次判断的时间step为250ms
  161. if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
  162. for step in range(time_sleep * 4):
  163. if not self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
  164. break
  165. time.sleep(0.25)
  166. self.target_img_url = browser.find_element_by_xpath(
  167. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  168. 'src')
  169. elif self.target_img_url.startswith('data:'):
  170. for step in range(int(max(1.5, time_sleep - 3) * 4)): # data: 类型的图片,最少等待 1.5s 去加载图片
  171. if not self.target_img_url.startswith('data:'):
  172. break
  173. time.sleep(0.25)
  174. self.target_img_url = browser.find_element_by_xpath(
  175. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  176. 'src')
  177. except Exception as e:
  178. logger.error(e)
  179. logger.error('当前第 {} 张缩减图片详情信息url获取信息失败,跳过处理'.format(idx + 1))
  180. continue
  181. # TODO 图片高清地址获取完毕,现在构建图片保存所需要的路径
  182. self.target_img_name = self.add_timestamp(self.clean_str(self.target_img_name)) + '.jpg'
  183. img_file_path = os.path.join(self.img_tmp_dir,
  184. self.target_img_name)
  185. # TODO 图片保存
  186. if self.target_img_url.startswith(
  187. 'https://encrypted-tbn0.gstatic.com/images?') or self.target_img_url.startswith('data:'):
  188. print(
  189. '总量:{}, 图片序号为:{},正在保存【缩减图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
  190. self.target_img_name,
  191. self.target_img_url[:150])
  192. # data: 链接太长,这里做一个截取
  193. )
  194. else:
  195. print(
  196. '总量:{}, 图片序号为:{},正在保存【高清图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
  197. self.target_img_name,
  198. self.target_img_url)
  199. )
  200. if self.target_img_url.startswith('http'):
  201. self.save_url_img(img_file_path)
  202. elif self.target_img_url.startswith('data:'):
  203. self.save_base64_img(self.target_img_url, img_file_path)
  204. # 重新爬取请求失败的高清图片的链接
  205. repeat_urls = self.repeat_urls
  206. self.repeat_spider(repeat_urls)
  207. browser.quit() # 浏览器退出
  208. def save_url_img(self, img_files_path):
  209. """
  210. 通过 url 请求保存图片
  211. :param img_files_path: 给定要保存的文件名的路径
  212. :return:
  213. """
  214. try:
  215. headers = {
  216. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
  217. }
  218. # TODO 增加连接重试次数(一共2次请求链接)
  219. # requests.adapters.DEFAULT_RETRIES = 1
  220. sess = requests.Session()
  221. sess.keep_alive = False # 关闭多余连接
  222. text = sess.get(self.target_img_url, headers=headers, stream=True, verify=False, timeout=5)
  223. with open(img_files_path, 'wb') as file:
  224. for i in text.iter_content(1024 * 10):
  225. file.write(i)
  226. except Exception as e:
  227. self.repeat_urls.append((self.target_img_url, img_files_path))
  228. logger.error(e, self.target_img_url)
  229. def save_base64_img(self, url, img_files_path):
  230. """
  231. 保存 base64 格式的图片
  232. :param url:
  233. :param img_files_path:
  234. :return:
  235. """
  236. import base64
  237. url = re.sub('.+base64,', '', url)
  238. img = base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
  239. fh = open(img_files_path, "wb")
  240. fh.write(img)
  241. fh.close()
  242. def screen_img(self, ele, img_files_path):
  243. """
  244. 给定需要截图的 element元素,进行截图
  245. :param ele: 需要截图的元素
  246. :param img_files_path: 图片的路径
  247. :return:
  248. """
  249. try:
  250. ele.screenshot(img_files_path)
  251. except Exception as e:
  252. logger.error('一些原因导致截图失败,跳过处理', e)
  253. def repeat_spider(self, urls, repeat_num=3):
  254. """
  255. 用于重复请求高清图片 get 失败的链接,下载图片
  256. urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
  257. repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
  258. """
  259. urls_num = len(urls)
  260. logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用requests的方式请求:\n'.format(urls_num))
  261. sucess_idx = [] # 保存成功的url 的索引列表
  262. for num in range(repeat_num):
  263. urls_num = len(urls)
  264. if urls_num == 0:
  265. break
  266. for idx,url_info in enumerate(urls):
  267. if idx not in sucess_idx:
  268. url = url_info[0]
  269. img_name = url_info[1]
  270. try:
  271. headers = {
  272. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
  273. }
  274. # TODO 增加连接重试次数(一共4次链接)
  275. sess = requests.Session()
  276. sess.mount('http://', HTTPAdapter(max_retries=3))
  277. sess.mount('https://', HTTPAdapter(max_retries=3))
  278. sess.keep_alive = False # 关闭多余连接
  279. text = requests.get(url, headers=headers, stream=True, verify=False, timeout=(4,5)) # connect 和 read 二者的 timeout
  280. with open(img_name, 'wb') as file:
  281. for i in text.iter_content(1024 * 10):
  282. file.write(i)
  283. text.close() # 关闭,很重要,确保不要过多的链接
  284. logger.info('使用requests的方式请求,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
  285. # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
  286. sucess_idx.append(idx)
  287. except Exception as e:
  288. logger.error(e)
  289. logger.error('使用requests的方式请求,重复爬取请求失败:{}'.format(url))
  290. time.sleep(0.5)
  291. if __name__ == '__main__':
  292. # TODO 参数
  293. head = False
  294. target_dir = r'target_dir'
  295. time_sleep = 3 # 网速好的时间可以下调,加载高清最长等待时间
  296. # logger.info(urls,head,keyword,target_dir)
  297. urls = [
  298. 'https://www.google.com/search?q=风景&newwindow=1&sxsrf=ALeKk002XUAM8lwptPWsSjuox8SjA1B7_A:1600079585015&source=lnms&tbm=isch&sa=X&ved=2ahUKEwimsZv6uOjrAhUNkJQKHW5HBD4Q_AUoAXoECAwQAw&biw=1920&bih=937']
  299. keyword = '风景'
  300. for url in urls:
  301. url = url.strip()
  302. # TODO 运行
  303. spider_obj = GoogleSpider(url, keyword, time_sleep, target_dir)
  304. # 创建一个浏览器
  305. browser = spider_obj.create_browser(head=head)
  306. # 下载图片
  307. spider_obj.get_main_page_info(browser=browser)

    (2)使用截图代替下载 缩减图

  1. tip:
  2. 1、删除:
  3. from utils import utils
  4. logger = utils.Logger_Hanlder.setup_logging(report_path='./log')
  5. 2、将所有的 logger语句转化为 print
  1. from selenium import webdriver
  2. from selenium.webdriver.common.by import By
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. from selenium.webdriver.support import expected_conditions as EC
  5. from selenium.common.exceptions import ElementNotInteractableException
  6. from selenium.webdriver.common.keys import Keys
  7. from requests.adapters import HTTPAdapter
  8. import argparse
  9. import time
  10. import os
  11. import re
  12. import requests
  13. import urllib3
  14. urllib3.disable_warnings() # 去除警告
  15. from utils import utils
  16. logger = utils.Logger_Hanlder.setup_logging(report_path='./log')
  17. class GoogleSpider():
  18. def __init__(self,url,keyword,time_sleep,target_dir,repeat_num,max_imgNum = None):
  19. self.url = url
  20. self.keyword = keyword
  21. self.repeat_num = repeat_num # 高清图片链接请求失败后重新爬取的次数
  22. self.time_sleep = time_sleep # 等待高清图片加载的时间
  23. self.max_imgNum = max_imgNum # 设置最大图片的下载量
  24. self.target_dir = target_dir
  25. self.img_tmp_dir = os.path.join(self.target_dir,
  26. self.add_timestamp(self.keyword))
  27. if not os.path.exists(self.img_tmp_dir):
  28. os.makedirs(self.img_tmp_dir)
  29. self.head = None # 浏览器是否存在头
  30. self.implicitly_wait_time = 5 # 隐形等待时间
  31. self.js_slide_wait = 30 # js 滑动窗口等待时间
  32. def clean_str(self,str_):
  33. """
  34. 清除字符串为图片命名时不合规的字符
  35. :return:
  36. """
  37. str_ = re.sub('[^\u4e00-\u9fa5A-Za-z\d]','',str_)
  38. return str_
  39. def add_timestamp(self,str_):
  40. """
  41. 为字符串添加时间搓,保证字符串唯一不重复性
  42. :param str_: str
  43. :return:
  44. """
  45. assert isinstance(str_,str)
  46. time_str = str(time.time()).replace('.','')
  47. str_ = str_ + time_str
  48. return str_
  49. def create_browser(self,head):
  50. """
  51. 创建一个浏览器的对象
  52. :param headless: 是否使用无头浏览器
  53. :return:
  54. """
  55. self.head = head
  56. options = webdriver.ChromeOptions()
  57. # 增加无头
  58. if not self.head:
  59. options.add_argument('--headless')
  60. # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
  61. options.add_argument("--window-size=4000,1600")
  62. options.add_argument('--disable-gpu')
  63. # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
  64. # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
  65. options.add_experimental_option("excludeSwitches", ['enable-automation'])
  66. # 关闭开发者模式
  67. options.add_experimental_option("useAutomationExtension", False)
  68. # 设置中文
  69. options.add_argument('lang=zh_CN.UTF-8')
  70. # 更换头部
  71. options.add_argument(
  72. 'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
  73. # 部署项目在linux时,其驱动会要求这个参数
  74. options.add_argument('--no-sandbox')
  75. browser = webdriver.Chrome(options=options)
  76. if self.head:
  77. browser.maximize_window()
  78. # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
  79. browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  80. "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
  81. })
  82. return browser
  83. def get_main_page_info(self,browser):
  84. """
  85. 获取主页面且拉至最底部,且获取所有图片详情页的链接地址
  86. :return:
  87. """
  88. browser.get(self.url)
  89. browser.implicitly_wait(self.implicitly_wait_time)
  90. # TODO 滑动到底的js代码
  91. js = """
  92. (function () {
  93. var y = document.documentElement.scrollTop;
  94. var step = 100;
  95. window.scroll(0, y);
  96. function f() {
  97. if (y < document.body.scrollHeight) {
  98. y += step;
  99. window.scroll(0, y);
  100. setTimeout(f, 100); //每两次间隔滑动的时间 100ms
  101. }
  102. else {
  103. window.scroll(0, y);
  104. document.title += "scroll-done";
  105. }
  106. }
  107. setTimeout(f, 1000); // 执行函数等待时间 1000ms
  108. })();
  109. """
  110. # TODO 执行滑动到底的操作
  111. browser.execute_script(js)
  112. # 等待窗口滑动结束
  113. for i in range(self.js_slide_wait):
  114. print('\rJS窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait,i+1),end='',flush=True)
  115. time.sleep(1)
  116. print()
  117. # TODO 点击 ‘ 加载更多的选项 ’
  118. try:
  119. browser.find_element_by_xpath('//div[@id="islmp"]/.//div[@jsname="i3y3Ic"]/.//input[@class="mye4qd"]').send_keys(Keys.ENTER)
  120. print('缓冲中...')
  121. time.sleep(8) # ‘加载更多’ 缓冲
  122. # TODO 执行点击加载更多继续滚动
  123. browser.execute_script(js)
  124. # 等待窗口滑动结束
  125. for i in range(self.js_slide_wait):
  126. print('\rJS加载更多图片窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
  127. time.sleep(1)
  128. print()
  129. except Exception as e:
  130. print(e, '网络不畅 或 该网页没有更多内容选项 .... ')
  131. # 获取图片详情页链接地址
  132. div_infos = browser.find_elements_by_xpath(
  133. "//div[@id='islmp']/.//div[contains(@class,'isv-r PNCib MSM1fd')]") # 结果是一个列表
  134. self.reduceImg_num = len(div_infos)
  135. if self.reduceImg_num == 0:
  136. assert Exception('网络链接 {} 错误\n 获取主页面class属性已更改'.format(self.url))
  137. logger.info('一共获取到 {} 张缩减图,且图片下载给定的最大的数量为{}张'.format(self.reduceImg_num,self.max_imgNum))
  138. # 定义重复请求的链接列表,保存 【{url,img_name},...】二元组列表
  139. self.repeat_urls = []
  140. # TODO 通过缩减图 DIV 获取高清图片的地址
  141. for idx,i in enumerate(div_infos):
  142. # 当图片下载超过给定的最大的数量时,停止爬取
  143. if self.max_imgNum is not None:
  144. if idx >= self.max_imgNum:
  145. logger.info("当图片下载超过给定的最大的数量时,强制停止")
  146. break
  147. try:
  148. data_id = i.get_attribute('data-id')
  149. except Exception as e:
  150. logger.error(e)
  151. logger.error('"data_id" 的属性值获取失败,可能网站已更改属性')
  152. continue
  153. # 图片详情页的 url 地址
  154. img_url = self.url + '#imgrc=' + data_id
  155. try:
  156. browser.get(img_url)
  157. self.target_img_url = browser.find_element_by_xpath(
  158. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  159. 'src')
  160. self.target_img_name = browser.find_element_by_xpath(
  161. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  162. 'alt')
  163. # 如果获取的url不以 data: 或者 http 开头,视为获取失败
  164. if not (self.target_img_url.startswith('data:') or self.target_img_url.startswith('http')):
  165. logger.info("第 {} 高清图片url: {} 格式错误,跳过".format(idx+1 , self.target_img_url))
  166. continue
  167. # 对是否详情页加载为高清图的url进行判断: https://encrypted-tbn0.gstatic.com/images? 开头属于缩减图
  168. # 因此对详情页进行最长为 time_sleep 时间的等待,每次判断的时间step为250ms
  169. if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
  170. for step in range(time_sleep * 4):
  171. if not self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
  172. break
  173. time.sleep(0.25)
  174. self.target_img_url = browser.find_element_by_xpath(
  175. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  176. 'src')
  177. elif self.target_img_url.startswith('data:'):
  178. for step in range( int(max(1.5,time_sleep - 3) * 4) ): # data: 类型的图片,最少等待 1.5s 去加载图片
  179. if not self.target_img_url.startswith('data:'):
  180. break
  181. time.sleep(0.25)
  182. self.target_img_url = browser.find_element_by_xpath(
  183. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
  184. 'src')
  185. except Exception as e:
  186. logger.error(e)
  187. logger.error('当前第 {} 张缩减图片详情信息url获取信息失败,跳过处理'.format(idx+1))
  188. continue
  189. # TODO 图片高清地址获取完毕,现在构建图片保存所需要的路径
  190. self.target_img_name = self.add_timestamp(self.clean_str(self.target_img_name)) + '.jpg'
  191. img_file_path = os.path.join(self.img_tmp_dir,
  192. self.target_img_name)
  193. # TODO 图片保存
  194. if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?') or self.target_img_url.startswith('data:'):
  195. logger.info(
  196. '总量:{}, 图片序号为:{},正在保存【截图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
  197. self.target_img_name,
  198. self.target_img_url[:150]) # data: 链接太长,这里做一个截取
  199. )
  200. # 保存截图
  201. ele_img = browser.find_element_by_xpath(
  202. "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img")
  203. self.screen_img(ele_img,img_file_path)
  204. else:
  205. logger.info(
  206. '总量:{}, 图片序号为:{},正在保存【高清图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
  207. self.target_img_name,
  208. self.target_img_url)
  209. )
  210. # 保存高清图
  211. self.save_url_img(img_file_path)
  212. time.sleep(0.5)
  213. # 重新爬取请求失败的高清图片的链接
  214. repeat_urls = self.repeat_urls
  215. repeat_num = self.repeat_num
  216. # self.repeat_spider_get(repeat_urls,repeat_num)
  217. self.repeat_spider_screen(repeat_urls,repeat_num)
  218. browser.quit() # 浏览器退出
  219. def save_url_img(self,img_files_path):
  220. """
  221. 通过 url 请求保存图片
  222. :param img_files_path: 给定要保存的文件名的路径
  223. :return:
  224. """
  225. try:
  226. headers = {
  227. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
  228. }
  229. # TODO 增加连接重试次数(一共2次请求链接)
  230. # requests.adapters.DEFAULT_RETRIES = 1
  231. sess = requests.Session()
  232. sess.keep_alive = False # 关闭多余连接
  233. text = sess.get(self.target_img_url, headers=headers, stream=True, verify=False, timeout=5)
  234. with open(img_files_path, 'wb') as file:
  235. for i in text.iter_content(1024 * 10):
  236. file.write(i)
  237. except Exception as e:
  238. self.repeat_urls.append((self.target_img_url,img_files_path))
  239. logger.error(e)
  240. logger.error("爬取请求失败:{}".format(self.target_img_url))
  241. def save_base64_img(self,url,img_files_path):
  242. """
  243. 保存 base64 格式的图片
  244. :param url:
  245. :param img_files_path:
  246. :return:
  247. """
  248. import base64
  249. url = re.sub('.+base64,','',url)
  250. img = base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
  251. fh = open(img_files_path, "wb")
  252. fh.write(img)
  253. fh.close()
  254. def screen_img(self,ele,img_files_path):
  255. """
  256. 给定需要截图的 element元素,进行截图
  257. :param ele: 需要截图的元素
  258. :param img_files_path: 图片的路径
  259. :return:
  260. """
  261. try:
  262. ele.screenshot(img_files_path)
  263. except Exception as e:
  264. logger.error('一些原因导致截图失败,跳过处理',e)
  265. def repeat_spider_get(self,urls,repeat_num):
  266. """
  267. 用于重复请求高清图片 get 失败的链接,下载图片
  268. urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
  269. repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
  270. """
  271. urls_num = len(urls)
  272. logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用requests的方式请求:\n'.format(urls_num))
  273. sucess_idx = [] # 保存成功的url 的索引列表
  274. for num in range(repeat_num):
  275. urls_num = len(urls)
  276. if urls_num == 0:
  277. break
  278. fail_num = 0 # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
  279. for idx,url_info in enumerate(urls):
  280. if idx not in sucess_idx:
  281. url = url_info[0]
  282. img_name = url_info[1]
  283. try:
  284. headers = {
  285. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
  286. }
  287. # TODO 增加连接重试次数(一共4次链接)
  288. sess = requests.Session()
  289. sess.mount('http://', HTTPAdapter(max_retries=3))
  290. sess.mount('https://', HTTPAdapter(max_retries=3))
  291. sess.keep_alive = False # 关闭多余连接
  292. text = requests.get(url, headers=headers, stream=True, verify=False, timeout=(4,5)) # connect 和 read 二者的 timeout
  293. with open(img_name, 'wb') as file:
  294. for i in text.iter_content(1024 * 10):
  295. file.write(i)
  296. text.close() # 关闭,很重要,确保不要过多的链接
  297. logger.info('使用requests的方式请求,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
  298. # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
  299. sucess_idx.append(idx)
  300. fail_num = 0 # 将该数字归 0
  301. except Exception as e:
  302. logger.error(e)
  303. logger.error('使用requests的方式请求,重复爬取请求失败:{}'.format(url))
  304. # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
  305. fail_num += 1
  306. if fail_num >= 6:
  307. break
  308. time.sleep(0.5)
  309. def repeat_spider_screen(self,urls,repeat_num):
  310. """
  311. 用于重复请求高清图片 去 截图图片
  312. urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
  313. repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
  314. """
  315. urls_num = len(urls)
  316. logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用浏览器截屏的方式来代替requests:\n'.format(urls_num))
  317. head = self.head
  318. browser = self.create_browser(head)
  319. browser.implicitly_wait(5)
  320. sucess_idx = [] # 保存成功的url 的索引列表
  321. for num in range(repeat_num):
  322. urls_num = len(urls)
  323. if urls_num == 0:
  324. break
  325. fail_num = 0 # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
  326. for idx,url_info in enumerate(urls):
  327. if idx not in sucess_idx:
  328. url = url_info[0]
  329. img_name = url_info[1]
  330. try:
  331. browser.get(url)
  332. ele = browser.find_element_by_xpath('//img')
  333. self.screen_img(ele = ele,img_files_path = img_name)
  334. logger.info('使用浏览器截屏的方式,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
  335. # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
  336. sucess_idx.append(idx)
  337. fail_num = 0 # 将该数字归 0
  338. except Exception as e:
  339. logger.error(e)
  340. logger.error('使用浏览器截屏的方式,重复爬取请求失败:{}'.format(url))
  341. # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
  342. fail_num += 1
  343. if fail_num >= 6:
  344. break
  345. time.sleep(0.5)
  346. if __name__ == '__main__':
  347. # argparse 回调函数
  348. def str2bool(v):
  349. if isinstance(v, bool):
  350. return v
  351. if v.lower() in ('yes', 'true', 't', 'y', '1'):
  352. return True
  353. elif v.lower() in ('no', 'false', 'f', 'n', '0'):
  354. return False
  355. else:
  356. raise argparse.ArgumentTypeError('Boolean value expected.')
  357. # TODO 参数
  358. # 创建对象
  359. parser = argparse.ArgumentParser()
  360. # 添加参数
  361. parser.add_argument('urls', help='main_page url',type=str,nargs='+') # url 地址,可以给多个
  362. parser.add_argument('--keywords', help='keywords',nargs='+',type=str) # 关键字
  363. parser.add_argument('--repeat_num', help='repeat spider num',type=int,default=1) # 高清图片url请求失败 重复获取的次数
  364. parser.add_argument('--max_imgNums', help='each url max imgs num',nargs='+',type=int,default=400) # 保存图片的最大数量
  365. parser.add_argument('--head', help='headless YES or NO',type=str2bool,default=True) # 是否开启无头浏览器
  366. # 使用parse_args解析参数
  367. args = parser.parse_args()
  368. urls = args.urls
  369. keywords = args.keywords
  370. repeat_num = args.repeat_num
  371. max_imgNums = args.max_imgNums
  372. head = args.head
  373. target_dir = r'C:\Users\liukang17\Desktop'
  374. time_sleep = 3 # 网速好的时间可以下调,加载高清最长等待时间
  375. logger.info("\n\n urls:{}-head:{}-keywords:{}-target_dir:{}-repeat_num:{}-max_imgNums:{} \n\n".format(urls,head,keywords,target_dir,repeat_num,max_imgNums))
  376. logger.error("\n\n urls:{}-head:{}-keywords:{}-target_dir:{}-repeat_num:{}-max_imgNums:{} \n\n".format(urls,head,keywords,target_dir,repeat_num,max_imgNums))
  377. tmp1_num = len(max_imgNums)
  378. tmp2_num = len(keywords)
  379. for idx,url in enumerate(urls):
  380. url = url.strip()
  381. # 判断 max_imgNums 与 keywords 列表索引是否越界
  382. if idx >= tmp1_num:
  383. max_imgNum = max_imgNums[-1]
  384. else:
  385. max_imgNum = max_imgNums[idx]
  386. if idx >= tmp2_num:
  387. keyword = keywords[-1]
  388. else:
  389. keyword = keywords[idx]
  390. # TODO 运行
  391. spider_obj = GoogleSpider(url,keyword,time_sleep,target_dir,repeat_num,max_imgNum)
  392. # 创建一个浏览器
  393. browser = spider_obj.create_browser(head=head)
  394. # 下载图片
  395. spider_obj.get_main_page_info(browser=browser)
  1. 执行脚本:
  2. cd C:\Users\****\Desktop\LanJunTools
  3. python google_image_main.py "https://www.google.com.tw/search?q=风景&source=lnms&tbm=isch&sa=X&ved=2ahUKEwijoaW6o7bsAhUEIIgKHUQPBeAQ_AUoAXoECBcQAw&biw=1366&bih=625" "https://www.google.com.tw/search?q=壁纸&tbm=isch&ved=2ahUKEwiRwNG7o7bsAhXENKYKHaUzBCcQ2-cCegQIABAA&oq=%E5%A3%81%E7%BA%B8&gs_lcp=CgNpbWcQAzICCAAyAggAMgIIADICCAAyBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB46BAgAEAQ6BggAEAUQHlCqd1iGogFg16MBaABwAHgAgAGoA4gBiAqSAQkwLjMuMi4wLjGYAQCgAQGqAQtnd3Mtd2l6LWltZ7ABAMABAQ&sclient=img&ei=VBWIX5HGDcTpmAWl55C4Ag&bih=625&biw=1366" --max_imgNums 900 200 --head 0 --keywords 风景 壁纸

 

二、利用 selenium 自动上传文件(图片/文本)

  1、利用 .send_keys( file_path ) 的方式上传 图片

        selenium处理文件或图片上传弹窗的三种方式(input框,robot类,autoIT3工具)

  2、selenium 操作 textarea 文本域上传文本

  1. selenium 对文本框的输入操作一般有两种形式,传统的是直接通过定位元素通过sendKeys()方法直接在文本框中输入信息。
  2. 但有时候我们可以通过xpath的方式将其进行定位,但却不能通过sendKeys()向文本框中输入文本信息。
  3. 这种情况下,也需要借助JavaScript 代码完成输入。

       HTML 文本域 

  1. <textarea id="id" style="width: 98%" cols="50" rows="5" class="txtarea">
  2. </textarea>
  3. ...
  4. ...

        第一种:

driver.find_element_by_id('id').sendKeys("需要输入的内容");

       第二种:

  1. text = '文本域上传的内容'
  2. js = "var kw = document.getElementById('kw') ;kw.value='{}';".format(text)
  3. driver.execute_script(js)

三、自动上传大众点评头像、评论

Directory_Hanlder 自定义库代码地址:https://blog.csdn.net/qq_16555103/article/details/107146429
失败,已放弃
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from selenium import webdriver
  4. from utils.utils import Directory_Hanlder
  5. from selenium.webdriver.common.keys import Keys
  6. from selenium.common.exceptions import ElementNotInteractableException
  7. import os #
  8. import numpy as np
  9. import pandas as pd
  10. import time
  11. import argparse
  12. class DumpMassage():
  13. def __init__(self,choice,head_img_dir = None, comments_signs_file = None):
  14. # 选择哪种方式执行 'img' 上传头像 'text' 上传文本 'all' 同时上传
  15. assert choice in ['img','text','all']
  16. self.choice = choice
  17. # 登录浏览器的参数
  18. self.log_in_url = "https://account.dianping.com/login?" # 登录点评网页的链接地址
  19. self.log_in_sleep = 15 # 登录页面扫码等待时间
  20. self.main_page = 'https://www.dianping.com/'
  21. # 上传头像图片的参数
  22. self.head_img_url = 'http://www.dianping.com/member/myinfo/setup/userface' # 头像上传的链接地址
  23. self.head_img_sleep = 2.5 # 上传图片等待时间提交,最小为 time_sleep,最大为 time_sleep + 1.5 的随机数
  24. self.head_img_dir = head_img_dir # 上传头像图片的目录路径
  25. # 评论与签名相关参数
  26. self.comments_signs_file = comments_signs_file # 上传文本数据的文件路径
  27. # 浏览器对象参数
  28. self.head = True
  29. self.implicitly_wait = 15
  30. # 浏览器初始化
  31. self.browser = self.create_browser(head=self.head)
  32. self.browser.implicitly_wait(self.implicitly_wait)
  33. self.browser = self.log_in_dianping(self.browser,self.log_in_url,time_sleep=self.log_in_sleep)
  34. # 浏览器打开主页面 且 再打开一个窗口
  35. # self.browser.get(self.main_page)
  36. # self.browser.find_element_by_xpath("//a[@class= 'item left-split username J-user-trigger']").send_keys(Keys.ENTER)
  37. self.browser.get(self.head_img_url) # 此时,浏览器其实已经有了两个窗口了{ 目前位于第一个窗口,即主窗口 },第一个窗口用来上传头像,第二个窗口用来上传文本数据
  38. self.windows = self.browser.window_handles
  39. def create_browser(self,head):
  40. """
  41. 创建一个浏览器的对象
  42. :param headless: 是否使用无头浏览器
  43. :return:
  44. """
  45. self.head = head
  46. options = webdriver.ChromeOptions()
  47. # 增加无头
  48. if not self.head:
  49. options.add_argument('--headless')
  50. # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
  51. options.add_argument("--window-size=4000,1600")
  52. options.add_argument('--disable-gpu')
  53. # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
  54. # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
  55. options.add_experimental_option("excludeSwitches", ['enable-automation'])
  56. # 关闭开发者模式
  57. options.add_experimental_option("useAutomationExtension", False)
  58. # 设置中文
  59. options.add_argument('lang=zh_CN.UTF-8')
  60. # 更换头部
  61. options.add_argument(
  62. 'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
  63. # 部署项目在linux时,其驱动会要求这个参数
  64. options.add_argument('--no-sandbox')
  65. browser = webdriver.Chrome(options=options)
  66. if self.head:
  67. browser.maximize_window()
  68. # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
  69. browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  70. "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
  71. })
  72. return browser
  73. def log_in_dianping(self,browser,url,time_sleep = 15):
  74. """
  75. 浏览器登录点评
  76. :param browser:
  77. :param url: 登录点评的链接
  78. :param time_sleep: 登录扫码等待的时间
  79. :return:
  80. """
  81. # 浏览器登录
  82. browser.get(url) # 获取路径
  83. time.sleep(0.3)
  84. browser.switch_to.frame((browser.find_element_by_xpath('//iframe')))
  85. browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  86. "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
  87. })
  88. browser.find_element_by_xpath('//span[@class="bottom-password-login"]').click()
  89. time.sleep(0.3)
  90. browser.find_element_by_id('tab-account').click()
  91. # 登录
  92. browser.find_element_by_id('account-textbox').clear()
  93. browser.find_element_by_id('account-textbox').send_keys('***********')
  94. time.sleep(2)
  95. browser.find_element_by_id('password-textbox').clear()
  96. browser.find_element_by_id('password-textbox').send_keys('***********') # password
  97. time.sleep(1)
  98. browser.find_element_by_id('login-button-account').click()
  99. # 登录等待
  100. time.sleep(3)
  101. return browser
  102. def load_head_img_paths(self,img_dir):
  103. """
  104. 给定头像图片目录路径,加载所有图片的路径
  105. :param img_dir:
  106. :return:
  107. """
  108. assert img_dir is not None
  109. img_paths,_ = Directory_Hanlder.list_dir_all_files(img_dir)
  110. img_nums = len(img_paths)
  111. self.img_paths = img_paths
  112. self.img_nums = img_nums
  113. return img_paths,img_nums
  114. def load_comments_sign(self,comments_path):
  115. """
  116. 加载文件【①去除空行数据 ②去除首尾空格】至Series中,保存每段文本所对应的行号
  117. :param comments_path: 文件的路径
  118. :return: Series
  119. """
  120. assert comments_path is not None
  121. # 将数据保存至 Series 中
  122. comments_ser = pd.Series()
  123. try:
  124. with open(comments_path,'r',encoding='utf-8-sig') as w:
  125. for row,line in enumerate(w.readlines()):
  126. # 对每一行的数据前后去除空格
  127. line = line.strip()
  128. # 判断去除空格后的数据是否有内容,只要有数据的内容【去除空行数据】
  129. if line:
  130. # 添加行号
  131. row_index = row + 1
  132. comments_ser.loc[row_index] = line
  133. except Exception as e:
  134. with open(comments_path, 'r', encoding='gbk') as w:
  135. for row, line in enumerate(w.readlines()):
  136. # 对每一行的数据前后去除空格
  137. line = line.strip()
  138. # 判断去除空格后的数据是否有内容,只要有数据的内容【去除空行数据】
  139. if line:
  140. # 添加行号
  141. row_index = row + 1
  142. comments_ser.loc[row_index] = line
  143. return comments_ser,len(comments_ser)
  144. def dump_head_img(self,url,browser,img_path,time_sleep=1.5):
  145. """
  146. 上传头像图片的函数,给定 一张头像图片地址进行上传,
  147. :param url:
  148. :param time_sleep: 上传图片等待时间提交, 最小为 time_sleep
  149. :return:
  150. """
  151. try:
  152. browser.find_element_by_xpath("//input[@capture='camera']").send_keys(img_path)
  153. except:
  154. # 当找不到元素的时候,重新请求一下页面
  155. browser.get(url)
  156. # 获取上传头像 ele 元素
  157. browser.find_element_by_xpath("//input[@capture='camera']").send_keys(img_path)
  158. # 上传图片等待时间提交,最小为 time_sleep
  159. tmp1_num = np.random.uniform(time_sleep, time_sleep + 1.5)
  160. time.sleep(tmp1_num)
  161. # 点击提交 ---- 使用 js 大法
  162. flag = True
  163. try:
  164. js = 'document.getElementById("J_usave").click();'
  165. browser.execute_script(js)
  166. # 判断url并非最初的美团图片,才进行打印
  167. dump_url = browser.find_element_by_xpath("//img[@id='J_bface']").get_attribute('src')
  168. if not dump_url.startswith('https://p0.meituan.net/userheadpic/chicken.png%40120w'):
  169. print('随机数等待上传图片时间为: {:.1f} , 上传的图片url为:{}'.format(tmp1_num,dump_url))
  170. if len(self.browser.find_elements_by_class_name('medi-btn-ashdisb')) == 0:
  171. print('找不到button的类属性 medi-btn-ashdisb ,判断图片点击失败')
  172. flag = False
  173. except Exception as e:
  174. flag = False
  175. print('\nERROR: \n',e)
  176. print('当前图片点击事件触发失败,上传失败,已跳过\n')
  177. # 上传后等待 1.6 - 2.5 s
  178. time.sleep(np.random.uniform(1.6,2.5))
  179. time.sleep(100)
  180. return browser,flag
  181. def dump_text(self,line,browser):
  182. """
  183. 上传文本
  184. :return:
  185. """
  186. url = "http://www.dianping.com/member/myinfo/setup/basic"
  187. browser.get(url)
  188. # TODO 给文本域上传文本
  189. js = "var kw = document.getElementById('J_sign') ;kw.value='{}';".format(line)
  190. browser.execute_script(js)
  191. time.sleep(1)
  192. # js = 'document.getElementsByClassName("btn-txt J_submit")[0].click();'
  193. browser.execute_script(js)
  194. return browser
  195. def run_img(self,browser):
  196. """
  197. 仅仅自动上传头像
  198. :param browser: 浏览器对象
  199. :return:
  200. """
  201. self.browser = browser
  202. # 获取 给定的头像目录路径 所有图片的路径
  203. img_paths,img_num = self.load_head_img_paths(self.head_img_dir)
  204. print('一共有 {} 张头像需要上传, 现在正在上传中....'.format(img_num))
  205. # 浏览器请求头像页面链接
  206. self.browser.get(self.head_img_url)
  207. for idx,head_img in enumerate(img_paths):
  208. # 每 10 张 图片重新请求下头像上传页面,防止假死状态
  209. if (idx+1) % 10 == 0:
  210. self.browser.get(self.head_img_url)
  211. time.sleep(np.random.uniform(0.8,1.4))
  212. # 防止后台检测,每上传25 张图片, 睡眠 60s 的时间
  213. if (idx + 1) % 25 == 0:
  214. for i in range(60):
  215. time.sleep(1)
  216. print('\r等待 60s 继续上传头像,现在是第{}s '.format(i+1),end='',flush=True)
  217. print()
  218. # 重新请求头像上传的网址
  219. self.browser.get(self.head_img_url)
  220. time.sleep(np.random.uniform(0.8, 1.4))
  221. # 上传头像
  222. self.browser,flag = self.dump_head_img(self.head_img_url,self.browser,head_img,time_sleep=self.head_img_sleep)
  223. if not flag:
  224. continue
  225. elif flag:
  226. print('第 {} 张头像图片-{} 上传成功!'.format(idx+1,head_img))
  227. print('头像 {} 张图片已全部上传完毕!'.format(img_num))
  228. return self.browser
  229. def run_comments(self):
  230. """"""
  231. # 更换第二个窗口
  232. self.browser.switch_to.window(self.windows[-1])
  233. # 执行 js 更换 window.navigator.webdriver 属性
  234. self.browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  235. "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
  236. })
  237. # 获取需要所有的文本数据
  238. comments,num = self.load_comments_sign(self.comments_signs_file)
  239. print(comments,num)
  240. for idx,line in enumerate(comments):
  241. # 上传文本数据
  242. self.browser = self.dump_text(line,self.browser)
  243. print('共 {} 条文本,第 {} 条内容: {} '.format(num,idx+1,line))
  244. time.sleep(2)
  245. return self.browser
  246. def run_all(self):
  247. pass
  248. def run(self):
  249. """
  250. 主函数,运行
  251. :return:
  252. """
  253. if self.choice is 'img':
  254. self.run_img(self.browser)
  255. elif self.choice is 'text':
  256. self.run_comments()
  257. elif self.choice is 'all':
  258. self.run_all()
  259. else:
  260. raise Exception("choice 参数输入有误! 从 ['img','text','all'] 选择一个 ")
  261. if __name__ == '__main__':
  262. head_img_dir = r'C:\Users\Hasee\Desktop\touxiang'
  263. comments_sign = r'C:\Users\Hasee\Desktop\作文.txt'
  264. choice = 'text'
  265. obj = DumpMassage(choice = choice,head_img_dir = head_img_dir,comments_signs_file=comments_sign)
  266. browser = obj.run()
  267. #退出浏览器
  268. browser.quit()

 

 

Reference

        python解码data:image开头的图片地址

        python 爬取 谷歌以及百度图片

 

 

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号