Python动态页面爬起

一、Ajax数据爬取

1.Ajax介绍

Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。 它不是一门编程语言,而是利用JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。发送Ajax请求到网页更新过程,简单分为以下3步:发送请求;解析内容;渲染网页。
Ajax具有特殊的请求类型,它叫作xhr。

2.Ajax数据爬取

# 首先,定义一个方法来获取每次请求的结果。 在请求时,page是一个可变参数,所以我们将它作为方法的参数传递进来,相关代码如下:
from  urllib.parse import  urlencode
import  requests
base url = ‘https://m.weibo.cn/api/container/getlndex?‘
headers = {
‘Host‘:  ‘m.weibo.cn‘,
‘Referer':‘https://m.weibo.cn/u/2830678474‘,
‘User-Agent‘:‘Mozilla/s.o (Macintosh;  Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML,  like Gecko)
Chrome/58.0.3029.110 Safari/537.36‘,‘X-Requested-With ‘:‘XMLHttpRequest‘,
}
def get_page(page)‘:
params = {
‘type‘:‘uid‘,
‘value‘:‘2830678474‘,
‘containerid‘:‘1076032830678474‘,
‘page‘: page
}
url = base_url + urlencode(params)
try:
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
    return response.json()
except requests.ConnectionError as e:
    print(‘ Error‘,  e.args)

# 随后,我们需要定义一个解析方法,用来从结果中提取想要的信息,比如这次想保存微博的id、正文、赞数、 评论数和转发数这几个内容,  那么可以先遍历cards,然后获取mblog 中的各个信息,赋值为一个新的字典返回即可:
from  pyquery import  PyQuery as pq
def parse _page (j son):
    if json:
    items  = j son. get(‘ data ‘) .get(‘cards ‘)
    for item  in  items:
        item = item.get(‘mblog‘)
        weibo = {}
        weibo[ ‘id‘] = item.get(‘id‘)
        weibo[‘text‘] = pq(item.get(‘text‘)). text()
        weibo[‘attitudes‘]  = item.get(‘attitudes_count‘)
        weibo [ ‘comments ‘] = item.get(‘comments_count‘)
        weibo[‘reposts‘] = item.get(‘reposts_count‘)
        yield weibo

# 最后,遍历一下page,一共10页,将提取到的结果打印输出即可:
if name ==  ‘main‘:
    for page in range(l, 11):
        json = get_page(page)
        results = parse_page(json)
    for result in results:
        print(result)

# 加一个方法将结果保存到MongoDB数据库:
from  pymongo import MongoClient
client = MongoClient ()
db = client [ ‘weibo‘ ]
collection = db[‘weibo‘]
def save_to_mongo(result):
    if collection.insert(result):
        print(‘save to Mongo‘)

二、Selenium库

Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。

1.声明浏览器对象

from  selenium import webdriver
browser = webdri ver. Chrome()
browser = webdriver. Firefox()
browser = webdri ver. Edge()
browser = webdriver. PhantomJS()
browser= webdriver.Safari() 

# 完成浏览器对象初始化并将其赋值为browser 对象。调用 browser对象,让其执行各个动作以模拟浏览器操作。

2.访问页面

from  selenium import webdnver
browser = webdriver.Chrome()
browser. get (’https://www.taobao.com’ )
print(browser.page_source)
browser. close() 

# 用get()方法来请求网页,参数传入链接URL即可。 

3.查找节点

# 单个节点
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
Selenium提供通用方法find_element(),它需要传入两个参数: 查找方式By和值。find_element(By.ID,id)
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get(‘https://www.taobao.com‘)
input_first = browser.find_element(By.ID,‘q‘)
print(input_first)
browser.close()

# 多个节点
要查找所有满足条件的节点,需要用find_elements()这样的方法

4.节点交互

Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。

from selenium import webdriver
import time 

browser = webdriver.Chrome()
browser.get(‘https://www.taobao.com‘)
input = browser.find_element_by_id(‘q‘)

# send_keys()方法用于输入文字
input.send_keys(‘iPhone‘)
time.sleep(1)

# clear()方法用于清空文字
input.clear()
input.send_keys(‘iPad‘)
button = browser.find_element_by_class_name(‘btn-search‘)

# click()方法用于点击按钮
button.click()

5.动作链

如鼠标拖曳、 键盘按键等,它们没有特定的执行对象,这些动作用另一种方式来执行,那就是动作链。

- 实现一个节点的拖曳操作,将某个节点从一处拖曳到另外一处

# 首先,打开网页中的一个拖曳实例,然后依次选中要拖曳的节点和拖曳到的目标节点,接着声明ActionChains对象并将其赋值为actions变量,然后通过调用actions变量的drag_and_drop()方法,  再调用perform()方法执行动作,此时就完成了拖曳操作
from  selenium import  webdnver
from  selenium.webdriver import  ActionChains
browser = webdriver.Chrome()
url =’http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable‘
browser.get(url)
browser.switch_to.frame(‘iframeResult‘)
source = browser.find_element_by_css selector(‘#draggable‘)
target= browser.find_element_by_css_selector(‘#droppable‘ )
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform() 

6.JavaScript执行

对于某些操作,Selenium API并没有提供。 比如,下拉进度条,它可以直接模拟运行JavaScript,
此时使用execute script()方法即可实现,代码如下:

from selenium import webdriver
browser= webdriver.Chrome()
browser. get (’https://www.zhihu.com/explore‘)
browser.execute_script(‘window.scrollTo(o, document.body.scrollHeight)’)
browser.execute_script(‘alert(”To Bottom”)‘) 

# 这里就利用execute script()方法将进度条下拉到最底部,然后弹出alert提示框。

7.获取节点信息

- 获取属性

# 使用get_attribute()方法来获取节点的属性
from  selenium import webdriver
from  selenium.webdriver import  ActionChains
browser = webdri ver. Chrome()
url = ‘https://www.zhihu.com/explore‘
browser. get ( url)
logo= browser.find_element_by_id(’zh-top-link-logo’)
print(logo)
print(logo.get_attribute(’class‘ )) 

- 获取文本值

from  selenium import webdriver
browser= webdriver.Chrome()
url =’https://www.zhihu.com/explore’
browser. get(url)
input = browser.find_element by class name(‘zu-top-add-question’)
print(input.text) 

- 获取id、位置、标签名和大小

from. selenium import  webdnver
browser = webdriver. Chrome()
url =’https://www.zhihu.com/explore‘
browser.get (url)
input= browser.find_element_by_class_name(’zu-top-add-question‘)
print(input.id)        # 节点id
print(input.location)  # 节点页面相对位置
print(input.tag_name)  # 标签名称
print(input.size)      # 节点大小

8.Frame切换

网页中有一种节点叫作iframe,也就是子Frame,相当于页面的子页面,它的结构和外部网页的结构完全一致。 Selenium打开页面后,它默认是在父级Frame里面操作,而此时如果页面中还有子Frame,它是不能获取到子Frame里面的节点的。 这时就需要使用switch_to.frame()方法来切换Frame。

import time
from  selenium import  webdriver
from  selenium.common.exceptions import  NoSuchElementException
browser = webdriver.Chrome()
url = ‘http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable‘
browser.get(url)
browser.switch_to.frame(‘iframeresult’)
try:
  logo= browser.find_element_by_class_name(‘logo‘)
except NoSuchElementException:
  print(’NO  LOGO‘)
browser.switch_to.parent_frame)
logo = browser. find_element_by_class_name(‘logo‘)
print(logo)
print(logo.text) 

首先通过switch_to. frame()方法切换到子Frame里面,然后尝试获取父级Frame 里的logo 节点(这是不能找到的),如果找不到的话,就会抛出NoSuchElementException异常,异常被捕捉之后,就会输出NO LOGO。 接下来,重新切换回父级Frame,然后再次重新获取节点,发现此时可以成功获取了。

- 隐式等待

使用隐式等待执行测试的时候,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛什1找不到节点的异常。 换句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间是0。

from  selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait (10)
browser.get(’https://www.zhihu.com/explore‘ )
input = browser. find_element_by_class_name(’zu-top-add-question’)
print(input) 

- 显式等待

隐式等中认为固定了等待时间,然而页面的加载时间会受到网络条件的影响。
显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。 如果在规定时间内加载出这个节点,就返回查找的节点;如果到了规定时间依然没有加载出来,则抛出超时异常。

# 首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions。 比如,这里传入了presence_of_element_located这个条件,代表节  点出现的意思,其参数是节点的定位元组,也就是ID为q的节点搜索框。
- 效果:在10秒内如果ID为q的节点(即搜索框)成功加载出来,就返回该节点;如果超过10秒还没有加载出来,就抛出异常。

from  selenium import webdriver
from  selenium.webdriver.common.by import  By
from  selenium.webdriver.support.ui import WebDriverWait
from  selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
browser.get(’https://www.taobao.com/’)
wait = WebDriverWait(browser, 10)
input = wait. until(EC. presence_of _element_located( (By. ID,’q’)))
button = wait.until(EC.element to be clickable((By.CSS_SELECTOR,’.btn search‘)))
print(input, button) 

9.前进、后退

浏览器时都有前进和后退功能,Selenium中分别通过forward()、back()方法实现。

import time
from  selenium import webdnver
browser = webdriver.Chrome()
browser. get (’https://www.baidu.com/’)
browser.get(‘https://www.taobao.com/’)
browser.get(’https://www.python.org/’)
browser.back()
time.sleep(l)
browser. forward()
browser. close() 

10.Cookies

from selenium import webdriver

browser = webdriver.Chrome()
browser.get(‘https://www.zhihu.com/explore‘)
print(browser.get_cookies())
browser.add_cookie({‘name‘:‘name‘,‘domain‘:‘www.zhihu.com‘,‘value‘:‘germey‘})
browser.delete_all_cookies()

11.选项卡管理

import  time
from  selenium import  webdnver
browser = webdriver. Chrome()
browser.get(’https://www.baidu.com‘)
browser.execute_script(’window. open()’)
print(browser. window _handles)
browser.switch_to_window(browser.window_handles[l])
browser.get(’https://www.taobao.com‘)
time.sleep(l)
browser.switch_to_window(browser.window_handles(0))
browser.get(’https://python.org‘)

12.异常处理

from  selenium import webdriver
from  selenium.common.exceptions import  TimeoutException, NoSuchElementExcephon
browser = webdriver.Chrome()
try:
  browser.get(‘https://www.baidu.com’)
except TimeoutException:
  print(‘ Time Out‘)
try:
  browser. find_element_by_id(‘ hello‘)
except NoSuchElementException:
  print(’No Element’)
finally:
  browser.close() 

三、Splash

Splash是一个JavaScript渲染服务,是一个带有HTTPAPI的轻量级浏览器,它对接了Python中的Twisted和QT库。 利用它,我们同样可以实现动态谊染页面的抓取。

  • 异步方式处理多个网页渲染过程;
  • 获取渲染后的页面的源代码或截图;
  • 通过关闭图片渲染或者使用Adblock规则来加快页面渲染速度;
  • 可执行特定的JavaScript脚本;
  • 可通过Lua脚本来控制页面渲染过程;
  • 获取渲染的详细过程并通过HAR( HTTP Archive )格式呈现

1.Splash Lua脚本

Splash可以通过Lua脚本执行一系列渲染操作,这样我们就可以用Splash来模拟类似Chrome、PhantomJS的操作。

- 入口及返回值

function main(splash, args)
    splash:go("http://www.baidu.com")
    splash:wait(o.s)
    local title = splash:evaljs(”document.title”)
    return {title=title}
end 

- 异步处理

function main(splash, args)
  local example_urls = {"www.baidu.com”,”www.taobao.com”,”www.zhihu.com‘’}
  local urls = args.urls or example_urls
  local results = {}
  for index,url in  ipairs(urls) do
    local ok, reason = splash:go(”http://”..url)
    if ok then
      splash:wait(2)
      results[url] = splash:png()
    end
  end return results
end

2.Splash对象属性

- args

# 此属性可获取加载时配置的参数,如URL
function main(splash, args)
    local url = args.url
end

- js_enabled

# 此属性是Splash的JavaScript执行开关,可以将其配置为true或false来控制是否执行JavaScript代码,默认为true。
function main(splash, args)
    splash:go(”https://www.baidu.com”)
    splash.js_enabled = false
    local title = splash:evaljs(”document.title")
    return {title=title}
end

- resource_timeout

# 此属性可以设置加载的超时时间,单位是秒。 如果设置为0或nil,代表不检测超时。
function main(splash)
    splash.resource_timeout = 0.1
    assert(splash:go(‘https://www.taobao.com‘))
    return splash:png()
end

- images_enabled

# 此属性可以设置图片是否加载,默认情况下是加载的。
function main(splash, args)
    splash.images_enabled = false
    assert(splash:go(’https://www.jd.com‘))
    return {png=splash:png()}
end 

- plugins_enabled

# 此属性可以控制浏览器插件是否开启。 默认情况下,此属性是false,表示不开启。
splash.plugins_enabled = true/false 

- scroll_position

# 通过设置此属性,可以控制页面上下或左右滚动。
function main(splash, args)
    assert(splash:go(‘https://www.taobao.com’))
    splash.scroll_position = {y=400}
    return {png=splash: png()}
end 

3.Splash对象方法

go()                 # 用于请求某个链接,模拟GET和POST请求。
ok, reason =  splash#go{url, baseurl=nil, headers=nil, http_method="GET", body=nil,  formdata=nil}
baseurl是资源加载相对路径,headers是请求头,http_method默认GET,body发POST请求时的表单数据,formdata是POST时的表单数据

wait()                # 控制页面等待时间
jsfunc()              # 可以直接调用JavaScript定义的方法,但是所调用的方法需要用双中括号包围,这相当于实现了JavaScript方法到Lua脚本的转换。
evaljs()              # 执行JavaScript代码并返回最后一条JavaScript语句的返回结果
runjs()               # 执行JavaScript代码,它与evaljs()的功能类似,但是更偏向于执行某些动作或声明某些方法。
autoload()            # 设置每个页面访问时自动加载的对象
call_later()          # 通过设置定时任务和延迟时间来实现任务延时执行,井且可以在执行前通过cancel()重新执行定时任务。
http_get()            # 模拟发送HTTP的GET请求
http_post()           # 用来模拟发送POST请求
set_content()         # 用来设置页面的内容
html()                # 用来获取网页的源代码
png()                 # 用来获取PNG格式的网页截图
jpeg()                # 用来获取JPEG格式的网页截图
har()                 # 用来获取页面加载过程
url()                 # 获取当前正在访问的URL
get_cookies()         # 获取当前页面的Cookies
add_cookies()         # 为当前页面添加Cookie
clear_cookies()       # 清除所有的Cookies
get_viewport_size()   # 获取当前浏览器页面的大小,即宽高
set_viewport_size()   # 设置当前浏览器页面的大小,即宽高
set_viewport_full()   # 设置浏览器全屏显示
set_user_agent()      # 设置浏览器的User-Agent
set_custom_headers()  # 设置请求头
select()              # 选中符合条件的第一个节点,如果有多个节点符合条件,则只会返回一个,其参数是css选择器
select_all()          # 选中所有符合条件的节点,其参数是css选择器
mouse_click()         # 模拟鼠标点击操作,传入的参数为坐标值x和y。此外,也可以直接选中某个节点,然后调用此方法

4.Splash API调用

render.html     # 此接口用于获取JavaScript渲染的页面的HTML代码,接口地址就是Splash的运行地址加此接口名称
import  requests
url = ‘http://localhost:8050/render.html?url=https://www.baidu.com‘
response = requests.get(url)
print(response.text) 

render.pug      # 此接口可以获取网页截图,它返回的是PNG格式的图片二进制数据
import  requests
url =‘http://localhost:8050/render.png?url=https://www.jd.com&wait=S&width=lOOO&height=700‘
response = requests.get(url)
with open(’taobao.png’, ‘wb ’) as f:
    f.write(response.content) 

render.jpeg     # 此接口可以获取网页截图,它返回的是JPEG格式的图片二进制数据
render.bar      # 此接口用于获取页面加载的HAR数据
render.json     # 此接口包含了前面接口的所有功能,返回结果是JSON格式
execute         # 此接口可用于实现与Lua脚本的对接。

5.Splash负载均衡配置

用Splash做页面抓取时,如果爬取的量非常大,任务非常多,用一个Splash服务来处理的话,未免压力太大了,此时可以考虑搭建一个负载均衡器来把压力分散到各个服务器上。 这相当于多台机器多个服务共同参与任务的处理,可以减小单个Splash服务的压力。

第一步:配置Splash服务;第二步:配置负载均衡,选用任意一台带有公网IP的主机来配置负载均衡。首先,在这台主机上装好Nginx,然后修改Nginx的配置文件nginx.conf;第三步:配置认证,Splash是可以公开访问的,如果不想让其公开访问,还可以配置认证,这仍然借助于Nginx。可以在server的location字段中添加auth_basic和auth basic user_file字段;第四步:测试。

http {
    upstream splash {
    least_conn;
    server 41.159.27.223:8050;
    server 41.159. 27. 221: 8050;
    server 41.159. 27. 9: 8050:
    server 41.159 .117 .119: 8050;
  }
  server {
    listen 8050;
    location / {
      proxy_pass http://splash;
      auth basic ”Restricted";
      auth basic user_file /etc/nginx/conf.d/.htpasswd;
      }
  }
}

import  requests
from  urllib.parse import  quote
import  re
lua  = ‘‘‘
  function main(splash, args)
  local treat = require("treat‘’)
  local response = splash:http_get(’‘http://httpbin.org/get")
  return treat.as_string(response.body
end
‘‘‘
url = ‘http://splash:8050/execute?lua_source=’+ quote(lua)
response = requests.get(url, auth=(‘admin‘,‘admin’))
ip = re.search(‘(\d+\.\d+\.\d+\.\d+)‘, response.text).group(l)
print(ip)

原文地址:https://www.cnblogs.com/Iceredtea/p/12215992.html

时间: 2024-10-10 02:00:47

Python动态页面爬起的相关文章

python动态网页爬取——四六级成绩爬取

需求: 四六级成绩查询网站我所知道的有两个:学信网(http://www.chsi.com.cn/cet/)和99宿舍(http://cet.99sushe.com/),这两个网站采用的都是动态网页.我使用的是学信网,好了,网站截图如下: 网站的代码如下: 1 <form method="get" name="form1" id="form1" action="/cet/query"> 2 3 <table

python scrapy爬取动态页面

preface:最近学习工作之外,有个异性朋友需要爬取动态网页的要求,输入关键词爬取某个专利网站在该关键词下的一些专利说明.以往直接python urllib2可破,但是那只是对于静态网页可破,但是对于用js等其他的生成的动态网页的话,则貌似不行(没试过).然后在网上找了些资料,发现scrapy结合selenium包好像可以.(之所以这么说,暂时卤主也还没实现,先记录下来.) #=====================根据官网中简单的介绍作个人理解=======================

python --selenium+phantomjs爬取动态页面广告源码

背景:利用爬虫,爬取网站页面广告元素,监控爬取元素的数目,定时发送监控邮件 #!/usr/bin/env python2.7 # -*- coding: utf-8 -*- ''' @xiayun @[email protected] #爬取网站内容,利用phantomjs:IP代理+修改UA+动态页面执行JS ''' from selenium import webdriver from selenium.webdriver.common.desired_capabilities import

Python爬虫-05:Ajax加载的动态页面内容

1. 获取AJAX加载动态页面的内容 1.1. Introduction 如果所爬取的网址是通过Ajax方式加载的,就直接抓包,拿他后面传输数据的文件 有些网页内容使用AJAX加载,只要记得,AJAX一般返回的是JSON,直接对AJAX地址进行post或get,就返回JSON数据了. 拿到JSAON,就是拿到了网页的数据 例子:http://www.kfc.com.cn/kfccda/storelist/index.aspx 这里有很多页数据,每一页的数据都是ajax加载的.如果你直接用pyth

Python开发入门与实战3-Django动态页面

3.Django动态页面 上一章节我们实现的helloworld视图是用来演示Django网页是创建的,它不是一个动态网页,每次运行/helloworld/,我们都将看到相同的内容,它类似一个静态HTML文件. 接下来我们将实现另一个视图,加入动态内容,例如当前日期和时间显示在网页上.通过简单的下一步,来演示Django的这个技术. 3.1.一个简单的动态页面例子 这个视图做两件事情: 获取服务器当前日期和时间,并返回包含这些值的HttpResponse .为了让Django视图显示当前日期和时

python爬爬爬之单网页html页面爬取

python爬爬爬之单网页html页面爬取 作者:vpoet 日期:大约在夏季 注:随意copy 不用告诉我 #coding:utf-8 import urllib2 Response=urllib2.urlopen("http://www.baidu.com"); Html=Response.read(); print Html; 运行结果: 再看看百度的源码: 是一样,没骗你吧

如何利用Python网络爬虫爬取微信朋友圈动态--附代码(下)

前天给大家分享了如何利用Python网络爬虫爬取微信朋友圈数据的上篇(理论篇),今天给大家分享一下代码实现(实战篇),接着上篇往下继续深入. 一.代码实现 1.修改Scrapy项目中的items.py文件.我们需要获取的数据是朋友圈和发布日期,因此在这里定义好日期和动态两个属性,如下图所示. 2.修改实现爬虫逻辑的主文件moment.py,首先要导入模块,尤其是要主要将items.py中的WeixinMomentItem类导入进来,这点要特别小心别被遗漏了.之后修改start_requests方

python动态爬取网页

简介 有时候,我们天真无邪的使用urllib库或Scrapy下载HTML网页时会发现,我们要提取的网页元素并不在我们下载到的HTML之中,尽管它们在浏览器里看起来唾手可得. 这说明我们想要的元素是在我们的某些操作下通过js事件动态生成的.举个例子,我们在刷QQ空间或者微博评论的时候,一直往下刷,网页越来越长,内容越来越多,就是这个让人又爱又恨的动态加载. 爬取动态页面目前来说有两种方法 分析页面请求 selenium模拟浏览器行为 1.分析页面请求 键盘F12打开开发者工具,选择Network选

爬取动态页面2

动态页面的爬取思路: 1.  ajax  -----数据放在 json 中,在里面是否有url 2.  js  数据   通过    搜索原页面上的数据关键字    :ctrl + f   , 全局搜索关键字 例子: 开始网站  url = 'https://www.xuexi.cn/' 爬取的页面1: url 1= 'https://www.xuexi.cn/f997e76a890b0e5a053c57b19f468436/018d244441062d8916dd472a4c6a0a0b.ht