需要用到的模块
from selenium import webdriver #浏览器驱动
from selenium.webdriver.chrome.options import Options #设置
# 其他模块
import time
import ssl
import threading #多线程下载
import urllib.request #下载
import urllib.error #下载
携带配置、创建浏览器。
def browser_get():
# 创建设置对象
chrome_options = Options()
# 向对象添加参数,手机模式。
chrome_options.add_experimental_option("mobileEmulation", { "deviceName": "Nexus 5" })
# 向设置添加headless模式。
chrome_options.add_argument('--headless')
# 设置驱动位置、传入设置对象
browser = webdriver.Chrome(r'F:\study_project\webpack\SeleniumDemo\chromedriver.exe',chrome_options = chrome_options)
# 打开url
browser.get('http://jandan.net/ooxx')
# 设置等待时间。
browser.implicitly_wait(10)
重要 设置页面滚动参数,让页面加载完全才能取得到xpath。
def browser_get():
... ...
js="document.documentElement.scrollTop="+ str(500)
browser.execute_script(js)
time.sleep(2)
取到资源列表。这里最好直接取到全部目标元素。否则会出现意外bug。download_pic
是下载方法,给他传入图像url就能实现下载。
def browser_get():
... ...
# 假设这些元素携带了图片url地址。
ul = browser.find_elements_by_xpath('//a[@class="view_img_link"]')
# 我们采用多线程来下载图片。
for li in ul:
threading.Thread(target=download_pic,args=(li.get_attribute("href"),)).start()
# 我们第一页内容已经下载完了,我们需要进入循环来下载页面内容了。下载完第一页,执行request_start函数。
request_start(browser,base_url)
进入翻页循环。
def request_start(browser,base_url):
# 我们在每页都需要滚动页面到下面来完成js渲染。
js="document.documentElement.scrollTop="+ str(8000)
browser.execute_script(js)
time.sleep(2)
browser.implicitly_wait(10)
# 在这里找到翻页元素调用其点击。
element=browser.find_element_by_xpath('//a[@title="Older Comments"][1]')
print('text--------{}'.format(element.text))
if element:
# 如果存在就点击下一页。给一个反应时间。慢一点...
element.click()
time.sleep(10)
# 和上面一样,继续找到页面所有携带图片url的元素
ul = browser.find_elements_by_xpath('//a[@class="view_img_link"]')
for li in ul:
threading.Thread(target=download_pic,args=(li.get_attribute("href"),)).start()
if ul:
#如果ul存在就不停的爬取。
return request_start(browser,base_url)
下载图片的方法
# 下载图片
def download_pic(url):
correct_url = url
if url.startswith('//'):
correct_url = url[2:]
if not url.startswith('http'):
correct_url = 'http://' + correct_url
print(correct_url)
headers = {
'Host': 'wx2.sinaimg.cn',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/61.0.3163.100 Safari/537.36 '
}
try:
req = urllib.request.Request(correct_url, headers=headers)
resp = urllib.request.urlopen(req)
pic = resp.read()
pic_name = correct_url.split("/")[-1]
with open(pic_save_path + pic_name, "wb+") as f:
f.write(pic)
except (OSError, urllib.error.HTTPError, urllib.error.URLError, Exception) as reason:
print(str(reason))
设置ssl上下文、定义主函数。
if __name__ == "__main__":
ssl._create_default_https_context = ssl._create_unverified_context
browser_get()
总结,用到的关键语句。
browser
.implicitly_wait(10) #设置等待超时
.find_elements_by_xpath() #返回列表
.find_element_by_xpath() #返回单个
.execute_script(js) #执行js
.add_experimental_option() #添加设置
js="document.documentElement.scrollTop="+ str(500) #页面滚动的js语句。
threading.Thread(target=fun,args=(**kwargs,)).start() #多线程
pix_h=640
js="document.documentElement.scrollTop="+ str(i*pix_h)
"return document.documentElement.scrollHeight.toString()+','+document.documentElement.scrollTop.toString()"
引用的包
# selenium
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
#一些系统和文件操作用于合并
import time
import os
from PIL import Image
封装这个函数。有些页面你需要点确定/关闭才能浏览,我们需要操作一下让浏览器自动点确定,只需要输入关闭按钮xpathnotify
。其中一部分准备。真正的循环结构下面说明。
def url_captrue(url_path='https://guazi.com/bj/buy/',pix_h=640,headless=True,deviceName="Nexus 5",exePath='F:\study_project\webpack\SeleniumDemo\chromedriver.exe',notify='/html/body/div[5]/div[2]/div/img'):
"""垂直合并多张图片
url_path - 打开的页面
pix_h - 手机高度。
headless - 是否使用无图模式
deviceName - 如果是手机,请设置设备名称。如果是浏览器请写deviceName=''
exePath - 驱动文件位置。
notify - 首页是否有通知,默认有。如无填写notify=''
"""
#创建浏览器设置
chrome_options = Options()
headlessflag=lambda x: '--headless' if x==True else ''
if headless:
chrome_options.add_argument(headlessflag(headless))
#添加设备参数
if deviceName!='' or deviceName!="" or deviceName!=None:
chrome_options.add_experimental_option("mobileEmulation", { "deviceName": deviceName })
#启动浏览器
wd = webdriver.Chrome(exePath,chrome_options = chrome_options)
wd.get(url_path)
#检测首页通知参数
wd.implicitly_wait(10)
if notify!='' or notify!="" or notify!=None:
wd.find_element_by_xpath(notify).click()
循环结构。这就刚才提到的几步。
def url_captrue(url_path='https://guazi.com/bj/buy/',pix_h=640,headless=True,deviceName="Nexus 5",exePath='F:\study_project\webpack\SeleniumDemo\chromedriver.exe',notify='/html/body/div[5]/div[2]/div/img'):
... ...(继承上面代码)
i=0
img_list = []
while i<8:
js="document.documentElement.scrollTop="+ str(i*pix_h)+";"
wd.execute_script(js)
js1 = "return document.documentElement.scrollHeight.toString()+','+document.documentElement.scrollTop.toString()"
js1_result = wd.execute_script(js1)
real_scroll_h, real_top = js1_result.split(',')[0], js1_result.split(',')[1]
print('{}-----{}'.format(real_scroll_h,real_top))
if real_top == str(i*pix_h): # 当前滚动条位置是都等于预期位置。是就截图
i += 1
#wd.save_screenshot('static/capture/wap/wap-'+filename + str(i)+'.png')
wd.get_screenshot_as_file('imgcontent\{}.png'.format(i))
img_list.append('imgcontent\{}.png'.format(i))
last_t = real_top
else:
# 如果本次设置失败,看这次的top和上一次记录的top值是否相等,相等则说明没有新加载内容,且已到页面底,跳出循环
if real_top != last_t: # 当前滚动条不等于本次预期位置。也不是上次预期位置,进入下次循环截图。
last_t = real_top
time.sleep(5) # 这里需要等待一下,对于滚动页面。看看还有没有加载。
print('加载一次')
else: # 当前滚动条不等于本次预期位置,而是上次预期位置。直接退出
#wd.get_screenshot_as_file('imgcontent\{}.png'.format(i))
#img_list.append('imgcontent\{}.png'.format(i))
break
image_merge(img_list, r'F:\study_project\webpack\SeleniumDemo\02SeleniumHeaderLess', 'all.png')
合并图像的代码:
def image_merge(images, output_dir, output_name='merge.jpg', restriction_max_width=None, restriction_max_height=None):
"""垂直合并多张图片
images - 要合并的图片路径列表
ouput_dir - 输出路径
output_name - 输出文件名
restriction_max_width - 限制合并后的图片最大宽度,如果超过将等比缩小
restriction_max_height - 限制合并后的图片最大高度,如果超过将等比缩小
"""
def image_resize(img, size=(1500, 1100)):
"""调整图片大小
"""
try:
if img.mode not in ('L', 'RGB'):
img = img.convert('RGB')
img = img.resize(size)
except Exception(e):
pass
return img
max_width = 0
total_height = 0
# 计算合成后图片的宽度(以最宽的为准)和高度
for img_path in images:
if os.path.exists(img_path):
img = Image.open(img_path)
width, height = img.size
if width > max_width:
max_width = width
total_height += height
# 产生一张空白图
new_img = Image.new('RGB', (max_width, total_height), 255)
# 合并
x = y = 0
for img_path in images:
if os.path.exists(img_path):
img = Image.open(img_path)
width, height = img.size
new_img.paste(img, (x, y))
y += height
if restriction_max_width and max_width >= restriction_max_width:
# 如果宽带超过限制
# 等比例缩小
ratio = restriction_max_height / float(max_width)
max_width = restriction_max_width
total_height = int(total_height * ratio)
new_img = image_resize(new_img, size=(max_width, total_height))
if restriction_max_height and total_height >= restriction_max_height:
# 如果高度超过限制
# 等比例缩小
ratio = restriction_max_height / float(total_height)
max_width = int(max_width * ratio)
total_height = restriction_max_height
new_img = image_resize(new_img, size=(max_width, total_height))
if not os.path.exists(output_dir):
os.makedirs(output_dir)
save_path = '%s/%s' % (output_dir, output_name)
new_img.save(save_path)
return save_path
编写主函数测试一下
if __name__ == "__main__":
url_captrue()