selenium接管已经打开的页面_selenium爬取Instagram

1c201ce3c9b3942f614550dae31fb18e.png

seleium安装完以后需要安装chromedriver,将下载下来的chromedriver可执行程序放到有环境变量的文件中 比如Anaconda 的Scripts文件夹。如果在命令行输入

chromedriver

c93f3506ba908c3bc36cd24a5ae9696c.png

返回东西则安装成功。

在使用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

42e040c80aa45405b90444844c774908.png

成功返回以后,来布置下本文的任务,打开

https://www.instagram.com/lotfiwoodwalker/​www.instagram.com

打开控制台切换成手机模式

3d030d7a76528517cad97aca57f2a32d.png

此时页面是这样的

bdcb363f1b64c6b5919383208a4f62ed.png

我们的任务就是把页面的帖子爬取下来,然后 帖子里的视频下载下来。感觉很简单,拉取到最下面以后审查一下元素

b1c0fcec54523463def858ad07db85ba.png

依然只有二十条,事实也是如此,不管你已经拉取了多少个帖子,这里只最多只保持20条的记录,我们有理由相信,这里做了优化,这20条的渲染也是当前窗口前后的帖子,所以我们要改变下策略,一开始我们想着的是把浏览器拉到底部,然后来解析整个page_source,现在必须每拉一次,就解析一次保存起来,而且还会很多重复的可能,需要做去重处理。那需要拉取多少次才能到达底部呢?

7b74533298f5c70fb8efa16a5a7942ed.png

我们根据帖子的数量来判断 一下抓取到的数量是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个帖子

c36aec5bd528d19e59f4b7c135004147.png

然后进行一次拖动,变成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秒钟,

3d942a0e8d940f09dd2aaa1cab6451f8.png

成功到达底部,不能再拖动,然后把解析逻辑写到每次拖动以后,

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是帖子的详情页,随便访问一个视频帖子的详情页,在详情页中审查元素

55a29a2e28fc49b82ccee31b9bc6bcdb.png

发现视频直接在标签里面,直接在浏览器就可以打开这个视频链接。怎么下载呢?

可以参考我另一篇文章:用python下载多媒体文件,在这里我提供另一种方式,

pip install youtube-dl

这是一个命令行下载工具,直接输入视频所在网站即可,并不需要我们去解析视频的原地址。

比如在命令行测试一个视频帖子,对了,下载视频的时候ss需要开启全局代理

youtube-dl https://www.instagram.com/p/BuJt3eFgLXE/

d57a8d0b98ced24411ddee062fde6744.png

视频成功下载下来,接下来我们用python代码来调用这个命令进行下载

import os

os.system('youtube-dl https://www.instagram.com/p/BuJt3eFgLXE/')

c7f447814931150ccd3cda09e78e73b8.png

运行的时候还带进度的。

于是我们可以把刚才爬取的到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-spider​github.com
64dc41198657cfeca842f1f6c286eb21.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值