引言css
自从学习了爬虫以后,天天不写个小爬虫爬爬小姐姐,都以为浑身难受:html
小姐姐是挺好看的,只是身体日渐消瘦而已,多喝养分快线就好!python
抓多了发现有一些小网站很狡猾,居然搞起反爬虫来了,不直接 生成数据,而是经过加载JS来生成数据,而后你打开Chrome浏览器的 开发者选项,而后你会发现Elements页面结构和Network抓包抓包 返回的内容居然是不同的,Network抓包那里居然没有对应的数据, 本该是数据的地方,居然是JS代码,好比煎蛋的妹子图:git
对于我这种不会JS的安卓狗来讲,不由感叹:github
抓不到数据怎么破,开始我还想着自学一波JS基本语法,再去模拟抓包 拿到别人的JS文件,本身再去分析逻辑,而后捣鼓出真正的URL,后来 仍是放弃了,有些JS居然他么的是加密的,并且要抓的页面那么多, 每一个这样分析分析到何时...web
后面意外发现有个自动化测试框架:Selenium 能够帮咱们处理这个问题。 简单说下这个东西有什么用吧,咱们能够编写代码让浏览器:chrome
而后这个东西是不支持浏览器功能的,你须要和第三方的浏览器 一块儿搭配使用,支持下述浏览器,须要把对应的浏览器驱动下载 到Python的对应路径下:json
Chrome:sites.google.com/a/chromium.… FireFox:github.com/mozilla/gec… PhantomJS:phantomjs.org/ IE:selenium-release.storage.googleapis.com/index.html Edge:developer.microsoft.com/en-us/micro… Opera:github.com/operasoftwa…windows
直接开始本节的内容吧~api
这个就很简单了,直接经过pip命令行进行安装:
sudo pip install selenium
复制代码
PS:想起以前公司小伙伴问过我pip在win上怎么执行不了,又另外下了不少pip, 其实若是你安装了Python3的话,已经默认带有pip了,你须要另外配置下环境 变量,pip的路径在Python安装目录的Scripts目录下~
Path后面加上这个路径就好~
由于Selenium是不带浏览器的,因此须要依赖第三方的浏览器,要调用第三方 的浏览器的话,须要下载浏览器的驱动,由于笔者用到是Chrome,这里就以 Chrome为例子吧,其余浏览器的自行搜索相关资料了!打开Chrome浏览器,键入:
chrome://version
复制代码
能够查看Chrome浏览器版本的相关信息,这里主要是关注版本号就好了:
61,好的,接下来到下面的这个网站查看对应的驱动版本号:
chromedriver.storage.googleapis.com/2.34/notes.…
好的,那就下载v2.34版本的浏览器驱动吧:
chromedriver.storage.googleapis.com/index.html?…
下载完成后,把zip文件解压下,解压后的chromedriver.exe拷贝到Python 的Scripts目录下。(这里不用纠结win32,在64位的浏览器上也是能够正常使用的!)
PS:Mac的话把解压后的文件拷贝到usr/local/bin目录下 Ubuntu的话拷贝到:usr/bin目录下
接下来咱们写个简单的代码来测试下:
from selenium import webdriver
browser = webdriver.Chrome() # 调用本地的Chrome浏览器
browser.get('http://www.baidu.com') # 请求页面,会打开一个浏览器窗口
html_text = browser.page_source # 得到页面代码
browser.quit() # 关闭浏览器
print(html_text)
复制代码
执行这段代码,会自动调起浏览器,而且访问百度:
而且控制台会输出HTML的代码,就是直接获取的Elements页面结构, JS执行完后的页面~接下来咱们就能够来抓咱们的煎蛋妹子图啦~
直接分析Elements页面结构,找到想要的关键结点:
明显这就是咱们抓取的小姐姐图片,复制下这个URL,看下咱们打印出的 页面结构有没有这个东西:
能够,很棒,有这个页面数据,接下来就走一波Beautiful Soup获取到咱们 想要的数据啦~
通过上面的过滤就可以拿到咱们的妹子图片URL:
随手打开一个验证下,啧啧:
看了下一页只有30个小姐姐,这显然是知足不了咱们的,咱们在第一次加载 的时候先拿到一波页码,而后就知道有多少页了,而后本身再去拼接URL加载 不一样的页面,好比这里总共又448页:
拼接成这样的URL便可:http://jandan.net/ooxx/page-448 过滤下拿到页码:
接下来就把代码补齐咯,循环抓取每一页的小姐姐,而后下载到本地, 完整代码以下:
import os
from selenium import webdriver
from bs4 import BeautifulSoup
import urllib.request
import ssl
import urllib.error
base_url = 'http://jandan.net/ooxx'
pic_save_path = "output/Picture/JianDan/"
# 下载图片
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))
# 打开浏览器模拟请求
def browser_get():
browser = webdriver.Chrome()
browser.get('http://jandan.net/ooxx')
html_text = browser.page_source
page_count = get_page_count(html_text)
# 循环拼接URL访问
for page in range(page_count, 0, -1):
page_url = base_url + '/page-' + str(page)
print('解析:' + page_url)
browser.get(page_url)
html = browser.page_source
get_meizi_url(html)
browser.quit()
# 获取总页码
def get_page_count(html):
soup = BeautifulSoup(html, 'html.parser')
page_count = soup.find('span', attrs={'class': 'current-comment-page'})
return int(page_count.get_text()[1:-1]) - 1
# 获取每一个页面的小姐姐
def get_meizi_url(html):
soup = BeautifulSoup(html, 'html.parser')
ol = soup.find('ol', attrs={'class': 'commentlist'})
href = ol.findAll('a', attrs={'class': 'view_img_link'})
for a in href:
download_pic(a['href'])
if __name__ == '__main__':
ssl._create_default_https_context = ssl._create_unverified_context
if not os.path.exists(pic_save_path):
os.makedirs(pic_save_path)
browser_get()
复制代码
运行结果:
看下咱们输出文件夹~
是的,贴那么多小姐姐,就是想骗你学Python!
PhantomJS没有界面的浏览器,特色:会把网站加载到内存并执行页面上的 JavaScript,由于不会展现图形界面,因此运行起来比完整的浏览器要高效。 (在一些Linux的主机上没有图形化界面,就不能用有界面的浏览器了, 能够经过PhantomJS来规避这个问题)。
Win上安装PhantomJS:
Ubuntu/MAC上安装PhantomJS:
sudo apt-get install phantomjs
复制代码
!!!关于PhantomJS的重要说明:
在今年的四月份,Phantom.js的维护者(Maintainer)宣布退出PhantomJS, 意味着这个项目项目可能不会再进行维护了!!!Chrome和FireFox也开始 提供Headless模式(无需吊起浏览器),因此,估计使用PhantomJS的小伙伴 也会慢慢迁移到这两个浏览器上。Windows Chrome须要60以上的版本才支持 Headless模式,启用Headless模式也很是简单:
selenium官方文档也写了:
运行的时候也会报这个警告:
CSDN登陆网站:passport.csdn.net/account/log…
分析下页面结构,不难找到对应的登陆输入框,以及登陆按钮:
咱们要作的就是在这两个结点输入帐号密码,而后触发登陆按钮, 同时把Cookie保存到本地,后面就能够带着Cookie去访问相关页面了~
先编写模拟登陆的方法吧:
找到输入帐号密码的节点,设置下本身的帐号密码,而后找到登陆 按钮节点,click一下,而后坐等登陆成功,登陆成功后能够比较 current_url是否发生了改变。而后把Cookies给保存下来,这里 我用的是pickle库,能够用其余,好比json,或者字符串拼接, 而后保存到本地。如无心外应该是能拿到Cookie的,接着就利用 Cookie去访问主页。
经过add_cookies方法来设置Cookie,参数是字典类型的,另外要先 访问get一次连接,再去设置cookie,否则会报没法设置cookie的错误!
看下右下角是否变为登陆状态就能够知道是否使用Cookie登陆成功了:
Seleninum做为自动化测试的工具,天然是提供了不少自动化操做的函数, 下面列举下我的以为比较经常使用的函数,更多可见官方文档: 官方API文档:seleniumhq.github.io/selenium/do…
PS:把element改成elements会定位全部符合条件的元素,返回一个List 好比:find_elements_by_class_name
有时须要在页面上模拟鼠标操做,好比:单击,双击,右键,按住,拖拽等 能够导入ActionChains类:selenium.webdriver.common.action_chains.ActionChains 使用ActionChains(driver).XXX调用对应节点的行为
对应类:selenium.webdriver.common.alert.Alert,感受应该用得很少...
若是你触发了某个时间,弹出了对话框,能够调用下述方法得到对话框: alert = driver.switch_to_alert(),而后能够调用下述方法:
切换窗口: driver.switch_to.window("窗口名") 或者经过window_handles来遍历 for handle in driver.window_handles: driver.switch_to_window(handle) driver.forward() #前进 driver.back() # 后退
driver.save_screenshot("截图.png")
如今的网页愈来愈多采用了 Ajax技术,这样程序便不能肯定什么时候某个元素彻底 加载出来了。若是实际页面等待时间过长致使某个dom元素还没出来,可是你的 代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。
为了不这种元素定位困难并且会提升产生 ElementNotVisibleException的几率。 因此 Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。
显式等待:
显式等待指定某个条件,而后设置最长等待时间。若是在这个时间尚未 找到元素,那么便会抛出异常了。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.PhantomJS()
driver.get("http://www.xxxxx.com/loading")
try:
# 每隔10秒查找页面元素 id="myDynamicElement",直到出现则返回
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
复制代码
若是不写参数,程序默认会 0.5s 调用一次来查看元素是否已经生成, 若是原本元素就是存在的,那么会当即返回。
下面是一些内置的等待条件,你能够直接调用这些条件,而不用本身 写某些等待条件了。
title_is title_contains presence_of_element_located visibility_of_element_located visibility_of presence_of_all_elements_located text_to_be_present_in_element text_to_be_present_in_element_value frame_to_be_available_and_switch_to_it invisibility_of_element_located element_to_be_clickable – it is Displayed and Enabled. staleness_of element_to_be_selected element_located_to_be_selected element_selection_state_to_be element_located_selection_state_to_be alert_is_present
隐式等待:
隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
复制代码
固然若是不设置,默认等待时间为0。
driver.execute_script(js语句) 好比滚动到底部: js = document.body.scrollTop=10000 driver.execute_script(js)
本节讲解了一波使用Selenium自动化测试框架来抓取JavaScript动态生成数据, Selenium需依赖于第三方的浏览器,要注意PhantomJS无界面浏览器过期的 问题,可使用Chrome和FireFox提供的HeadLess来替换;经过抓取煎蛋妹子 图以及模拟CSDN自动登陆的例子来熟悉Selenium的基本使用,仍是收货良多的。 固然Selenium的水仍是很深的,当前咱们可以使用它来应付JS动态加载数据页面 数据的抓取就够了。
最近天气略冷,各位小伙伴记得适时添衣~ 另外这周由于事比较多,就先断更了,下周再见,接下里要啃的骨头是 Python多线程,目测得啃好几节,敬请期待~
顺道记录下本身的想到的东西:
本节源码下载:
本节参考文献:
来啊,Py交易啊
想加群一块儿学习Py的能够加下,智障机器人小Pig,验证信息里包含: Python,python,py,Py,加群,交易,屁眼 中的一个关键词便可经过;
验证经过后回复 加群 便可得到加群连接(不要把机器人玩坏了!!!)~~~ 欢迎各类像我同样的Py初学者,Py大神加入,一块儿愉快地交流学♂习,van♂转py。