seleium安装完以后需要安装chromedriver,将下载下来的chromedriver可执行程序放到有环境变量的文件中 比如Anaconda 的Scripts文件夹。如果在命令行输入
chromedriver
返回东西则安装成功。
在使用selenium进行自动化测试中我们有时会遇到这样的情况:我们需要手动打开浏览器,进入到所需的页面,执行一些手动任务,如输入表单、输入验证码,登陆成功后,然后再开始运行自动化脚本。这种情况下如何使用selenium来接管先前已打开的浏览器呢?这里给出Google Chrome浏览器的解决方案。我们可以利用Chrome DevTools协议。它允许客户检查和调试Chrome浏览器。正式输入命令
chrome.exe --remote-debugging-port=9222 --user-data-dir="D:packageselenium"
对于-remote-debugging-port值,可以指定任何打开的端口。
对于-user-data-dir标记,指定创建新Chrome配置文件的目录。它是为了确保在单独的配置文件中启动chrome,不会污染你的默认配置文件。
还有,不要忘了在环境变量中PATH里将chrome的路径添加进去。
环境变量配置 chrome所在位置,仅供参考
# win
C:Program Files (x86)GoogleChromeApplication
# mac
/Applications/Google Chrome.app/Contents/MacOS
mac下也同理
'Google Chrome' --remote-debugging-port=9222 --user-data-dir="/Users/chenpin/Downloads/package/seleium"
跑完命令之后会有一个新的浏览器弹出来,手动打开百度以后,先来写段简单的脚本
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
driver = webdriver.Chrome(options=chrome_options)
print(driver.title)
我们这里就是连接上刚才用命令打开的chrome,并且打印当前页面的title
成功返回以后,来布置下本文的任务,打开
https://www.instagram.com/lotfiwoodwalker/www.instagram.com打开控制台切换成手机模式
此时页面是这样的
我们的任务就是把页面的帖子爬取下来,然后 帖子里的视频下载下来。感觉很简单,拉取到最下面以后审查一下元素
依然只有二十条,事实也是如此,不管你已经拉取了多少个帖子,这里只最多只保持20条的记录,我们有理由相信,这里做了优化,这20条的渲染也是当前窗口前后的帖子,所以我们要改变下策略,一开始我们想着的是把浏览器拉到底部,然后来解析整个page_source,现在必须每拉一次,就解析一次保存起来,而且还会很多重复的可能,需要做去重处理。那需要拉取多少次才能到达底部呢?
我们根据帖子的数量来判断 一下抓取到的数量是1,842 把逗号处理一下
html = driver.page_source
doc = pq(html)
thread_res = doc.find('.g47SY:first').text()
thread_num = "".join(list(filter(lambda x: x in '1234567890', thread_res)))
观察一开始进入页面的时候,有8个帖子
然后进行一次拖动,变成16条,那我们就假设每拉1次,是8条帖子,那么我们就要拖动的次数是,这种计算是保守估计,只会多,不会少,可以保证在这个次数下可以拖到底部
times = math.ceil(thread_num/8)
拖动页面的函数
def browse_action():
driver.execute_script( 'window.scrollTo(0, document.body.scrollHeight)')
利用javascript的语法,拖动的距离是整个页面的高度,意思就是拉到底部。
接下来测试一下
html = driver.page_source
doc = pq(html)
thread_res = doc.find('.g47SY:first').text()
thread_num = "".join(list(filter(lambda x: x in '1234567890', thread_res)))
scroll_times = math.ceil(int(thread_num)/8)
for i in range(scroll_times):
browse_action()
time.sleep(1)
每拖动一下暂停1秒钟,
成功到达底部,不能再拖动,然后把解析逻辑写到每次拖动以后,
for i in range(scroll_times):
browse_action()
time.sleep(1)
html = driver.page_source
html = html.replace('xmlns', 'another_attr')
doc = pq(html);
items = doc.find('.v9tJq ._bz0w').items()
for item in items:
item_ = pq(item)
is_video = "true" if item_.find('.u7YqG') else "false"
url = 'https://www.instagram.com' + item_.find('a').attr('href')
pattern = re.compile('.*p/(.*)/.*?')
results = re.findall(pattern,url)
result_id = results[0]
video_urls.append({'url': url, 'id': result_id, 'is_video': is_video})
帖子都爬下来了,保存的时候is_video来表示这个帖子是否是视频。
url是帖子的详情页,随便访问一个视频帖子的详情页,在详情页中审查元素
发现视频直接在标签里面,直接在浏览器就可以打开这个视频链接。怎么下载呢?
可以参考我另一篇文章:用python下载多媒体文件,在这里我提供另一种方式,
pip install youtube-dl
这是一个命令行下载工具,直接输入视频所在网站即可,并不需要我们去解析视频的原地址。
比如在命令行测试一个视频帖子,对了,下载视频的时候ss需要开启全局代理
youtube-dl https://www.instagram.com/p/BuJt3eFgLXE/
视频成功下载下来,接下来我们用python代码来调用这个命令进行下载
import os
os.system('youtube-dl https://www.instagram.com/p/BuJt3eFgLXE/')
运行的时候还带进度的。
于是我们可以把刚才爬取的到mongodb的视频遍历下载
from utils import *
import os
def get_video():
res = read_mongo({'is_video': 'true'})
lis = res
for item in lis:
os.system('youtube-dl {}'.format(item['url']))
if __name__ == '__main__':
get_video()
这样按顺序调用不会让系统压力很大... 如果不关心系统累不累,可以来个多进程的方式
from utils import *
import os
from multiprocessing import Pool
def down(url):
os.system('youtube-dl {}'.format(url))
def get_video():
res = read_mongo({'is_video': 'true'})
lis = res
groups = [item['url'] for item in lis]
pool = Pool()
pool.map(down,groups)
if __name__ == '__main__':
get_video()
这样的话,如果你的系统多个cpu,噼里啪啦一下子就能把所有视频搞定,网速够快的话
迷之警告:尽管selenium可以让我们省去对接口的分析,省去了各种参数的构造,然而在网络不稳定的情况仍很可能导致整个爬虫中断,没办法继续下去,只能重新来过。
源代码请参考
wuzhenbin/Instagram-spidergithub.com