python爬虫入门,如何高效地爬大量数据

爬虫(Spider),反爬虫(Anti-Spider),反反爬虫(Anti-Anti-Spider)
之间恢宏壮阔的斗争…

 

  • 小莫想要某站上全体的电影,写了标准的爬虫(基于HttpClient库),不断地遍历某站的影视列表页面,根据Html 剖判电影名字存进自身的数据库。

  • 本条站点的运转小黎意识有个别时间段诉求量陡增,分析日志发掘都是IP(xxx.xxx.xxx.xxx)那个客户,而且 user-agent 依旧Python-urllib/2.7 ,基于这两点剖断非人类后直接在服务器上封闭扼杀。

  • 小莫电影只爬了大意上,于是也本着的转移了下战略:1. user-agent
    模仿百度(“Baiduspider…”),2. IP每爬半个钟头就换三个IP代理。

  • 小黎也意识了对应的生成,于是在服务器上安装了贰个频率限制,每秒钟超越124遍呼吁的再屏蔽IP。
    相同的时间考虑到百度家的爬虫有望会被误伤,想想市镇部门每月几八万的投放,于是写了个剧本,通过
    hostname 检查下这么些 ip 是或不是真的百度家的,对这一个 ip
    设置多少个白名单。

  • 小莫开采了新的界定后,想着作者也不急着要那一个多少,留给服务器慢慢爬吧,于是修改了代码,随机1-3秒爬三回,爬12回苏息10秒,天天只在8-12,18-20点爬,隔几天还停息一下。

  • 小黎瞧着新的日志头都大了,再设定法则比相当的大心会挫伤真实顾客,于是准备换了七个思路,当3个刻钟的总央浼超越肆十九回的时候弹出三个验证码弹框,没有科学输入的话就把
    IP 记录进黑名单。

  • 小莫看到验证码有些傻脸了,可是亦不是尚未主意,先去读书了图像识别(关键词
    PIL,tesseract),再对验证码实行了二值化,分词,形式操练之后,总来讲之末了识别了小黎的验证码(关于验证码,验证码的辨识,验证码的反识别也是多少个恢宏壮丽的埋头单干史…),之后爬虫又跑了起来。

  • 小黎是个坚强的好同学,看到验证码被攻占后,和支出同学研商了调换下开拓方式,数据并不再间接渲染,而是由前端同学异步获取,何况经过
    JavaScript 的加密库生成动态的 token,同期加密库再进行模糊。

  • 指鹿为马过的加密库就没有章程了么?当然不是,可以稳步调试,找到加密原理,可是小或许策画用如此耗费时间耗力的点子,他抛弃了遵照HttpClient的爬虫,选拔了放置浏览器引擎的爬虫(关键词:PhantomJS,Selenium),在浏览器引擎运营页面,直接获得了科学的结果,又一遍得到了对方的数额。

  • 小黎:…..

Selenium

爬虫(Spider),反爬虫(Anti-Spider),反反爬虫(Anti-Anti-Spider),那之间的加油恢宏壮阔…

 Selenium是三个Web的自动化测量检验工具,最早是为网址自动化测量试验而支付的,类型像大家玩游戏用的开关Smart,能够按钦命的命令自动操作,不一样是Selenium
可以间接运行在浏览器上,它帮助全体主流的浏览器(富含PhantomJS那一个无分界面包车型客车浏览器)。

Day 1

小莫想要某站上全部的影片,写了标准的爬虫(基于HttpClient库),不断地遍历某站的摄像列表页面,依照Html 分析电影名字存进本人的数据库。
这一个站点的运营小黎开采某些时刻段央求量陡增,解析日志开采都以IP(1.1.1.1)那一个顾客,况兼 useragent 依然 JavaClient1.6
,基于这两点决断非人类后一向在Nginx 服务器上封闭扼杀。

Selenium
能够依赖我们的通令,让浏览器自动加载页面,获取须求的多少,以至页面截屏,可能判定网址上一点动作是否发生。

Day 2

小莫电影只爬了八分之四,于是也本着的转移了下战略:1. useragent
仿照百度(“Baiduspider…”),2. IP每爬半个钟头就换贰个IP代理。
小黎也意识了相应的变通,于是在 Nginx
上设置了三个效能限制,每分钟超越1贰十六次呼吁的再屏蔽IP。
相同的时间考虑到百度家的爬虫有不小也许会被误伤,想想市集机构每月几拾万的排泄,于是写了个本子,通过
hostname 检查下那一个 ip 是还是不是真的百度家的,对这个 ip 设置三个白名单。

Selenium
本身不带浏览器,不协理浏览器的魔法,它须要与第三方浏览器结合在一块儿能力使用.

Day 3

小莫开采了新的限制后,想着笔者也不急着要那么些数量,留给服务器慢慢爬吧,于是修改了代码,随机1-3秒爬一次,爬13回小憩10秒,每一天只在8-12,18-20点爬,隔几天还休憩一下。
小黎瞅着新的日志头都大了,再设定准则不当心会危机真实客户,于是策画换了二个思路,当3个时辰的总诉求当先伍12遍的时候弹出多个验证码弹框,未有标准科学输入的话就把
IP 记录进黑名单。

下载selenium webdriver
‘geckodriver.exe’,下载好后存放python目录里面

Day 4

小莫看到验证码有个别傻脸了,但是亦非从未有过办法,先去学习了图像识别(关键词
PIL,tesseract),再对验证码实行了二值化,分词,形式练习今后,识别了小黎的验证码(关于验证码,验证码的辨识,验证码的反识别也是贰个恢弘壮丽的斗争史,这里先不张开….),之后爬虫又跑了四起。
小黎是个坚强的好同学,看到验证码被夺回后,和支出同学研讨了调换下开垦情势,数据并不再直接渲染,而是由前端同学异步获取,并且经过
js 的加密库生成动态的
token,同有时间加密库再实行模糊(特别首要的步调的确有网址这样做,参见腾讯网的登陆流程)。

firefox的目录也要增添到情状变量中

Day 5

模糊过的加密库就从未有过章程了么?当然不是,能够渐渐调试,找到加密原理,可是小或然计划用这么耗费时间耗力的措施,他遗弃了基于
HttpClient的爬虫,选拔了安置浏览器引擎的爬虫(关键词:PhantomJS,Selenium),在浏览器引擎中js
加密脚本算出了不错的结果,又贰遍得到了对方的数码。
小黎:…..

爬虫与发爬虫的自强不息还在后续。
然则事实上应用时候,一般大家做到依据 IP
限制频次就终止了,除非十分的大旨的多少,不会再扩充更加多的评释,终究工程的题目二分一是花费的难点。

至于高效部分,一些 Tips:
1.尽量削减央求次数,能抓列表页就不抓实际情况页
2.毫不只看 Web 网址,还应该有 App 和 H5,他们的反爬虫措施一般非常少
3.假若真的对品质供给极高,能够思虑二十四线程(一些早熟的框架如
scrapy都已援助),以致布满式

 

作者:申玉宝
链接:

 

Selenium Curry有个叫 WebDriver 的
API。WebDriver 有一点儿像能够加载网址的浏览器,可是它也能够像
BeautifulSoup 也许另外 Selector
对象一样用来搜寻页面元素,与页面上的要素进行互动
(发送文书、点击等),以及实施另外动作来运维网络爬虫。

selenium快捷入门

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from selenium import webdriver

# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys

#创建浏览器对象
driver = webdriver.Firefox()

driver.get("http://www.baidu.com")

#打印页面标题“百度一下你就知道”
print driver.title

#生成当前页面快照
driver.save_screenshot("baidu.png")

# id="kw"是百度搜索框,输入字符串“微博”,跳转到搜索中国页面
driver.find_element_by_id("kw").send_keys(u"微博")

# id="su"是百度搜索按钮,click() 是模拟点击
driver.find_element_by_id("su").click()

# 获取新的页面快照
driver.save_screenshot(u"微博.png")

# 打印网页渲染后的源代码
print driver.page_source

# 获取当前页面Cookie
print driver.get_cookies()

# ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')

# ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')

# 输入框重新输入内容
driver.find_element_by_id("kw").send_keys("test")

# 模拟Enter回车键
driver.find_element_by_id("su").send_keys(Keys.RETURN)

# 清除输入框内容
driver.find_element_by_id("kw").clear()

# 生成新的页面快照
driver.save_screenshot("test.png")

# 获取当前url
print driver.current_url

# 关闭当前页面,如果只有一个页面,会关闭浏览器
# driver.close()

# 关闭浏览器
driver.quit()

1.页面操作

假诺有上边包车型地铁输入框

<input type="text" name="user-name" id="passwd-id" />

找寻办法

# 获取id标签值
element = driver.find_element_by_id("passwd-id")
# 获取name标签值
element = driver.find_element_by_name("user-name")
# 获取标签名值
element = driver.find_elements_by_tag_name("input")
# 也可以通过XPath来匹配
element = driver.find_element_by_xpath("//input[@id='passwd-id']")

2.恒定成分的主意

find_element_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

3.鼠标动作

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from selenium import webdriver

# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains

#创建浏览器对象
driver = webdriver.Firefox()

driver.get("http://www.baidu.com")

#鼠标移动到某处
action1 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action1).perform()

#鼠标移动到某处单击
action2 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action2).click(action2).perform()

#鼠标移动到某处双击
action3 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action3).double_click(action3).perform()

# 鼠标移动到某处右击
action4 = driver.find_element_by_id("su")
ActionChains(driver).move_to_element(action4).context_click(action4).perform()

4.Select表单

相遇下来框需求接纳操作时,Selenium特意提供了Select类来拍卖下拉框

# 导入 Select 类
from selenium.webdriver.support.ui import Select

# 找到 name 的选项卡
select = Select(driver.find_element_by_name('status'))

# 
select.select_by_index(1)
select.select_by_value("0")
select.select_by_visible_text(u"xxx")

如上是三种选用下拉框的法子,它能够遵照目录来抉择,能够依据值来摘取,能够依靠文字来挑选。注意:

  • index 索引从 0 开始
  • value是option标签的一个属性值,并非显得在下拉框中的值
  • visible_text是在option标签文本的值,是显得在下拉框的值

整整裁撤方法

select.deselect_all()

5.弹窗管理

当页面出现了弹窗提示

alert = driver.switch_to_alert()

6.页面切换

一个浏览器料定会有为数十分多窗口,所以我们自然要有法子来促成窗口的切换。切换窗口的法子如下:

driver.switch_to.window("this is window name")

7.页前面进和滞后

操作页面包车型地铁进化和落后效率:

driver.forward()     #前进
driver.back()        # 后退

实例
模拟登入douban网址

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

driver = webdriver.Firefox()
driver.get("http://www.douban.com")

# 输入账号密码
driver.find_element_by_name("form_email").send_keys("158xxxxxxxx")
driver.find_element_by_name("form_password").send_keys("zhxxxxxxxx")

# 模拟点击登录
driver.find_element_by_xpath("//input[@class='bn-submit']").click()

# 等待3秒
time.sleep(3)

# 生成登陆后快照
driver.save_screenshot(u"douban.png")

driver.quit()

 动态页面模拟点击—>>>爬取斗鱼全部房间名,听大伙儿数

(1)首先解析‘’下一页‘’的class变化,要是否终极一页的时候,‘下一页’的class如下

 图片 1

(2)假使到了最后一页,‘下一页’变为遮蔽,点击不了,class变为如下

图片 2

(3)找到个房屋的名字和观者人数的class

图片 3

(4)代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import unittest
from selenium import webdriver
from bs4 import BeautifulSoup as bs

class douyu(unittest.TestCase):
    # 初始化方法,必须是setUp()
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.num = 0
        self.count = 0

    # 测试方法必须有test字样开头
    def testDouyu(self):
        self.driver.get("https://www.douyu.com/directory/all")

        while True:
            soup = bs(self.driver.page_source, "lxml")
            # 房间名, 返回列表
            names = soup.find_all("h3", {"class" : "ellipsis"})
            # 观众人数, 返回列表
            numbers = soup.find_all("span", {"class" :"dy-num fr"})

            # zip(names, numbers) 将name和number这两个列表合并为一个元组 : [(1, 2), (3, 4)...]
            for name, number in zip(names, numbers):
                print u"观众人数: -" + number.get_text().strip() + u"-\t房间名: " + name.get_text().strip()
                self.num += 1
                #self.count += int(number.get_text().strip())

            # 如果在页面源码里找到"下一页"为隐藏的标签,就退出循环
            if self.driver.page_source.find("shark-pager-disable-next") != -1:
                    break

            # 一直点击下一页
            self.driver.find_element_by_class_name("shark-pager-next").click()

    # 测试结束执行的方法
    def tearDown(self):
        # 退出Firefox()浏览器
        print "当前网站直播人数" + str(self.num)
        print "当前网站观众人数" + str(self.count)
        self.driver.quit()

if __name__ == "__main__":
    # 启动测试模块
    unittest.main()

爬取的结果:

图片 4

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website