python抓取动态网页(数据怎么破()())
优采云 发布时间: 2021-10-09 15:02python抓取动态网页(数据怎么破()())
介绍
自从学了爬虫,每天不写个爬虫*敏*感*词*姐就觉得不爽:
*敏*感*词*姐长得还不错,就是身体越来越瘦了,多喝点营养快递吧!
(快来学Python爬虫,一起爬爬可爱的*敏*感*词*姐~)
抓了太多,发现有些小网站很狡猾,开始反爬虫了。它们不直接生成数据,而是通过加载JS生成数据,然后你打开Chrome浏览器的开发者选项,然后你会发现Elements页面的结构和网络抓包返回的内容不一样. 网络抓包中没有对应的数据。数据应该放的地方竟然是JS代码,比如煎蛋的少女图:
">
对于我这种不懂JS的安卓狗,不禁感叹:
">
抓不到数据怎么破?一开始想自学一波JS基础语法。然后我去模拟抓包来获取别人的JS文件。JS竟然被加密了,要爬的页面太多了。什么时候分析每个这样的分析...
">
我偶然发现有一个自动化测试框架:Selenium 可以帮助我们处理这个问题。简单说说这个东西的使用,我们可以写代码让浏览器:
然后这个东西不支持浏览器功能。您需要在第三方浏览器中使用它。支持以下浏览器,需要将对应的浏览器驱动下载到Python对应的路径:
Chrome: /a/chromium....FireFox: /mozilla/gec...PhantomJS: /IE: /index.htmlEdge: /en-us/micro...Opera: /operasoftwa...
下面直接开始本节的内容吧~
1.安装硒
这个很简单,直接通过pip命令行安装:
sudo pip install selenium
复制代码
PS:我记得我公司小伙伴问我为什么在win上不能执行pip,我下载了很多pip。其实如果你安装Python3,它默认已经自带pip了。您需要配置额外的环境变量,pip。路径在Python安装目录的Scripts目录下~
">
在Path后面加上这个路径就行了~
">2.下载浏览器驱动
因为 Selenium 没有浏览器,所以需要依赖第三方浏览器。如果要调用第三方浏览器,需要下载浏览器的驱动。由于作者使用的是 Chrome,所以我们以 Chrome 为例。其他 浏览器自行搜索相关信息!打开 Chrome 浏览器并输入:
chrome://version
复制代码
可以查看Chrome浏览器版本的相关信息,这里主要注意版本号:
">
61.好的,那么到下面网站查看对应的驱动版本号:
/2.34/notes....
">
好的,接下来下载v2.34版本的浏览器驱动:
/index.html?...
">
下载完成后,解压zip文件,将解压后的chromedriver.exe复制到Python Scripts目录下。(这里不用担心win32,64位浏览器可以正常使用!)
PS:对于Mac,将解压后的文件拷贝到usr/local/bin目录下,再拷贝到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执行后的页面~接下来就可以抓取我们的煎蛋少女图了~
3.Selenium 简单实战:抢炒蛋妹图
直接分析Elements页面的结构,找到你想要的关键节点:
">
显然这是我们抓到的那个*敏*感*词*姐的照片。复制这个网址,看看我们打印出来的页面结构是否收录这个东西:
">
是的这很好。有了这个页面数据,我们就来一波美汤获取我们想要的数据吧~
">
经过上面的过滤,我们就可以得到我们妹图的URL:
">
只需打开一个验证,啧:
">
">
我看到下一页只有30个*敏*感*词*姐,这对我们来说显然不够。第一次加载的时候,我们得到一波页码,然后我们就知道有多少页了,然后我们去拼接URL加载差异。例如,这里总共有 448 页:
">
只需将其拼接到此 URL 中:过滤以获取页码:
">
">
接下来,我将填写代码,循环抓取每个页面上的*敏*感*词*姐,并将其下载到本地。完整代码如下:
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 + '/' + 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!
">4.PhantomJS
PhantomJS 没有界面浏览器。特点: 它将网站加载到内存中并在页面上执行JavaScript。因为它不显示图形界面,所以它比完整的浏览器运行效率更高。(如果某些Linux主机上没有图形界面,有界面的浏览器是不能使用的,可以使用PhantomJS来规避这个问题)。
在 Win 上安装 PhantomJS:
在 Ubuntu/MAC 上安装 PhantomJS:
sudo apt-get install phantomjs
复制代码
!!!关于 PhantomJS 的重要说明:
今年 4 月,Phantom.js 的维护者宣布退出 PhantomJS,这意味着该项目可能不再维护!!!Chrome 和 FireFox 也开始提供 Headless 模式(不需要挂掉浏览器),所以估计使用 PhantomJS 的小伙伴会慢慢迁移到这两个浏览器。Windows Chrome 需要 60 以上的版本才能支持 Headless 模式。启用 Headless 模式也很简单:
">
selenium 的官方文档中还写道:
">
运行时也会报这个警告:
">5.Selenium实战:模拟登录CSDN并保存Cookie
CSDN登录网站:/account/log...
分析页面结构,不难发现对应的登录输入框和登录按钮:
">
">
我们要做的就是在这两个节点输入账号密码,然后触发登录按钮,并将cookie保存到本地,然后就可以带着cookie访问相关页面了~
首先写一个方法来模拟登录:
">
找到你输入账号密码的节点,设置你的账号密码,然后找到登录按钮节点,点击它,然后等待登录成功。登录成功后,可以对比current_url是否发生了变化。然后保存Cookies,这里我使用的是pickle库,你可以使用其他的,比如json,或者字符串拼接,然后保存到本地。如果没有意外,应该可以拿到Cookie,然后使用Cookie访问主页。
">
通过 add_cookies 方法设置 Cookie。参数是字典类型。另外一定要先访问get链接,再设置cookie,否则会报无法设置cookie的错误!
通过查看右下角是否变为登录状态就可以知道是否使用Cookie登录成功:
">6.Selenium 常用函数
Seleninum 作为自动化测试的工具,自然提供了很多自动化操作的功能。下面是我觉得比较常用的函数,更多的可以看官方文档:官方API文档:seleniumhq.github.io/selenium/do...
1) 定位元素
PS:将元素更改为元素将定位所有符合条件的元素并返回一个列表,例如:find_elements_by_class_name
2) 鼠标操作
有时需要在页面上模拟鼠标操作,如:单击、双击、右键、按住、拖动等,可以导入ActionChains类:mon.action_chains.ActionChains使用ActionChains(driver).XXX调用对应节点的行为
3) 弹出窗口
对应类:mon.alert.Alert,感觉用的不多...
如果触发某个时间,弹出对话框,可以调用如下方法获取对话框:alert = driver.switch_to_alert(),然后调用如下方法即可:
4)页面前进、后退、切换
切换窗口:driver.switch_to.window("window name") 或者在driver.window_handles中遍历window_handles获取句柄:driver.switch_to_window(handle)driver.forward()# forward driver.back()#返回
5) 页面截图
driver.save_screenshot("Screenshot.png")
6) 页面等待
现在越来越多的网页使用 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_istitle_containspresence_of_element_locatedvisibility_of_element_locatedvisibility_ofpresence_of_all_elements_locatedtext_to_be_present_in_elementtext_to_be_present_in_element_valueframe_to_be_available_and_switch_to_itinvisibility_of_element_locatedelement_to_be_clickable - 它显示和Enabled.staleness_ofelement_to_be_selectedelement_located_to_be_selectedelement_selection_state_to_beelement_located_selection_state_to_bealert_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。
7.执行JS语句
driver.execute_script(js语句)如滚动到底部:js = document.body.scrollTop=10000driver.execute_script(js)
概括
本节介绍一波使用 Selenium 自动化测试框架来捕获 JavaScript 动态生成的数据。Selenium 需要依赖第三方浏览器。注意 PhantomJS 无界面浏览器的过时问题。您可以使用 Chrome 和 FireFox 提供的 HeadLess 来替换它。; 通过抓取煎蛋女孩图片,模拟CSDN自动登录的例子,熟悉Selenium的基本使用,还是收获不少。当然,Selenium 的水还是很深的。目前我们可以用它来应对JS动态加载数据页面数据的抓取。
最近有点冷,大家记得及时加衣服哦~另外,因为这周事情比较多,先把换的破了。下周见。下一个要啃的骨头是 Python 多线程。我可以在视觉上,恭敬地啃几节经文。敬请期待~
">
顺便写下你的想法:
下载本节源码:
/coder-pig/R...
本节参考资料:
来吧,Py 交易
想加群一起学Py可以加小猪智障机器人,验证信息收录:python,python,py,Py,加群,交易,混蛋之一关键词 可以通过;
">
验证通过后回复群获取群链接(不要破机器人!!!)~~~欢迎像我这样的各类Py初学者和Py大神加入,一起交流学习♂ Xi, van ♂转向py。
">