启用 ChromeDriver
def start_requests(self):
"""使用 selenium 获取 cookie"""
# 获得 Options(操作)对象
chrome_option = Options()
# 添加到实例私有属性 self._arguments(论据)(list), 作为后续 webdriver 设置启动选项
chrome_option.add_argument('--disable-extensions') # 禁用扩展
# 添加到实例私有属性 self._experimental_options(实验选择)(dict), 第一个参数为 key, 第二个参数为 value进行赋值
# 也是作为后续 webdriver 启动设置选项
chrome_option.add_experimental_option('debuggerAddress', '127.0.0.1:9222') # 调试设置
# 获取当前目录相对路径 string
item_dir = os.path.dirname(os.path.abspath(__file__))
# 打开 webdriver 启用配置
with open(item_dir + r'/setting.conf') as f:
exe_key = f.read()
with open(item_dir + r'/executable_path.conf') as f:
exe_path = json.loads(f.read())['chrome'][exe_key]
# 传入可执行文件绝对路径, 此前 options 实例, 生成 browser 实例
browser = webdriver.Chrome(executable_path=exe_path[0], chrome_options=chrome_option)
# 调用实例 get 进入对应 web 页面
browser.get(self.start_urls[0])
# 放大 browser window
try:
browser.maximize_window()
except:
pass
模拟登录
# 避免输入框存在未知字符
browser.find_element_by_css_selector('input[id="loginname"]').send_keys(Keys.CONTROL + 'a')
# 定位到账号输入框, 输入账号
browser.find_element_by_css_selector('input[id="loginname"]').send_keys(WEIBO_CONFIG['account'])
# 避免输入框存在未知字符
browser.find_element_by_css_selector('input[type="password"]').send_keys(Keys.CONTROL + 'a')
# 定位到密码输入框, 输入密码
browser.find_element_by_css_selector('input[type="password"]').send_keys(WEIBO_CONFIG['password'])
# 定位到登录按钮, 触发点击事件
browser.find_element_by_css_selector('div[node-type="normal_form"] a[node-type="submitBtn"]').click()
验证码识别
针对动态验证码,处理验证码识别
截图当前验证码
# 给定循环条件
login_status = False
while not login_status:
try:
# 避免 web 页面响应时间过慢
time.sleep(10)
# 定位登录成功后 web 页面中的特定元素
browser.find_element_by_css_selector('em[class="W_ficon ficon_mail S_ficon"]')
# 已找到, 改变条件变量
login_status = True
# 跳出循环
break
# 未找到登录成功页面指定元素
except:
pass
try:
# 设置验证码图片, 保存相对路径
captcha_code = BASE_DIR + r'\image\captcha_code.png'
# 设置样本图片, 相对路径
check_image = BASE_DIR + r'\image\check_image.png'
# 寻找是否弹出验证码图片
captcha_element = browser.find_element_by_css_selector('img[node-type="verifycode_image"]')
# 获取元素属性 src
captcha_url = captcha_element.get_attribute('src')
# 判断是否包含 http / https (判断是否为 url)
if 'http' in captcha_url or 'https' in captcha_url:
# 引入第三方库, pyautogui(主要使用其截图功能)
import pyautogui
# 传入定位图片路径(string), 若定位成功可获取实例对象属性;
# Box(left=1111, top=111, width=33, height=33), 可以下标索引/关键字取出
point_coords = pyautogui.locateOnScreen(check_image)
try:
# 取出 x, y, width, height
point_coord = [point_coords.left, point_coords.top, point_coords.width, point_coords.height]
except KeyError as e:
print('not found : {} . error:{}'.format(check_image, e))
try:
# 验证码修正左侧,顶部,宽度和高度 px
correct = [120, -90, 30, 0]
# 调用 zip 函数, 列表推导式方式, 对位相加数组中的元素, 获得修正后的坐标
point_coord = tuple([px + p for px, p in zip(correct, point_coord)])
# 调用 screenshot 入口, 传入图片保存路径, region=坐标
pyautogui.screenshot(captcha_code, region=point_coord)
print('captcha code image screenshot success!!!!!')
except Exception as e:
print(str(e))
调用第三方服务,识别验证码
# 调用 exists 函数, 传入路径, 判断验证码图片是否存在
if os.path.exists(captcha_code):
# 实例化自定义工具类
DC = DataConvert()
# 取出保存验证码, 字节二进制数据
image_data = open(captcha_code, 'rb').read()
# 调用工具实例 -> 英文数字验证码识别方法, 传入二进制数据, 取出 pic_str key 的 value
captcha_result = DC.check_english_captcha(image_data)['pic_str']
print('receive code : <{}>'.format(captcha_result))
# 定位到验证码输入框(因为是JS动态加载的, 不点击不会改变), 触发点击事件
browser.find_element_by_css_selector('input[name="verifycode"]').click()
print('----click input----')
# 定位到验证码输入框, 输入验证码
browser.find_element_by_css_selector('input[class="W_input W_input_focus"]'
).send_keys(captcha_result)
print('-----input captcha code success------')
# 点击登录按钮
browser.find_element_by_css_selector(
'div[node-type="normal_form"] a[class="W_btn_a btn_32px "]').click()
print('----click login button-----')
# 调用系统处理模块, 删除文件函数, 删除验证码图片
os.remove(captcha_code)
获取cookie
except:
pass
# 循环执行以下代码
for i in range(3):
# 调用 browser 实例中, 执行 JavaScript 代码方法, 以下参数为 JavaScript 代码(执行鼠标下滑操作)
browser.execute_script('window.scrollTo(0, document.body.scrollHeight); var lenOfPage=document.body.scrollHeight; return lenOfPage;')
time.sleep(3)
# 获取 cookies
cookies = browser.get_cookies()
# 列表推导式获取 cookie-dict, 保存对应 cookie, 调用工具类 dict 合并方法, 合并 dict
cookie = DataConvert.merge_dicts([{cookie['name']: cookie['value']} for cookie in cookies])
# 存储 cookie
pickle.dump(cookie, open(BASE_DIR + '/cookie/weibo.cookie', 'wb'))
for url in self.start_urls:
yield scrapy.Request(url=url, cookies=cookie, dont_filter=True)