博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python3 爬虫
阅读量:7121 次
发布时间:2019-06-28

本文共 14012 字,大约阅读时间需要 46 分钟。

Python3 开发环境配置

请求库安装

需要用到的Python库来实现HTTP请求操作,如:Requests,Selenium,Aiotttp等。

  1. Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作。
  2. ChromeDriver驱动Chrome浏览器完成相应的操作。 在 chromedriver 所在的路径下执行。

sudo mv chromedriver /usr/bin

注意可能会遇到一下错误:
csrutil: failed to modify system integrity configuration. This tool needs to be executed from the Recovery OS.
遇到这种情况需要先关机,再开机并按住command+r键,进入恢复模式。在终端执行csrutil disable关闭SIP。

如果控制台有类似输出,则表示chromedriver 的环境变量配置好了。

from selenium import webdriverbrowser = webdriver.Chrome()复制代码

运行之后会弹出一个空白的Chrome浏览器。

3. Aiohttp是一个提供异步Web服务的库,Aiohttp的异步操作可以借助async/await关键字。
4. LXML的安装,支持HTML和XML的解析
5. BeautifulSoup的安装,这个库的HTML和XML解析器是依赖于LXML库。
6. pyquery也是一个强大的网页解析工具,它提供了和jQuery类似的语法来解析HTML文档,支持CSS选择器。

安装数据库

1.mysql 轻量级的关系型数据库,以表的形式存储数据
2.MongDB是由C++编写的非关系型数据库,是一个基于分布式文件储存的开源数据系统,其内容存储形式类似Json对象。 3.Redis 是一个基于内存的高效的非关系型数据库

brew install redis复制代码

启动Redis服务器

brew services start redisredis-server /usr/local/etc/redis.conf//关闭和重启brew services stop redisbrew services restart redis复制代码

4.PyMySQL python3中想要将数据存储在mysql中需要借助于PyMySQL来操作。

pip3 install pymysql复制代码

验证安装

>>> import pymysql>>> pymysql.VERSION(0, 9, 2, None)>>>复制代码

爬虫框架

#####一. PySplider强大的网络爬虫框架

pip3 install pyspider复制代码

在python3.7上会报如下错:

Traceback (most recent call last):  File "/usr/local/bin/pyspider", line 6, in 
from pyspider.run import main File "/usr/local/lib/python3.7/site-packages/pyspider/run.py", line 231 async=True, get_object=False, no_input=False): ^SyntaxError: invalid syntax复制代码

原因是因为async从python3.7开始不能用作参数名了

#####二. Scrapy

pip3 install Scrapy复制代码

####三. ScrapySplash

ScrapySplash 是一个Scrapy钟支持JavaScript的渲染工具,它的安装分为两个部分,一个是Splash服务的安装,安装方式Docker,安装之后会启动一个splash的服务,可以通过它的接口来实现JavaScript页面的加载。另外一个是ScrapySplsh的Python库安装,安装之后即可在Scrapy中使用Slpash服务。

安装Splash

docker run -p 8050:8050 scrapinghub/splash复制代码

ScrapySplash的安装

pip3 install scrapy-splash复制代码

####四. ScrapyRedis的安装

ScrapyRedis是Scrapy分布式的扩展模块,可以实现Scrapy分布式爬虫的搭建。

pip3 install scrapy-redis复制代码

安装测试

$ python3>>> import scrapy_redis复制代码

####五.部署相关库的安装

1.Docker的安装

brew cask install docker复制代码

2.Scrapyd 的安装

Scraypd是一个用于部署和运行Scrapy项目的工具,可以将Scrapy项目上传到云主机并通过API来控制它的运行。

pip3 install scrapyd复制代码

3.ScrapydClient的安装

pip3 install scrapyd-client复制代码

安装成功之后会有一个部署命令,叫做 scrapyd-deploy。

scrapyd-deploy -h复制代码

4.ScrapydAPI的安装

pip3 install python-scrapyd-api复制代码

可以直接请求它提供的api即可获取当前主机的Scrapy 任务运行状况。

from scrapyd_api import ScrapydAPIscrapyd = ScrapydAPI('http://localhost:6800')print(scrapyd.list_projects())复制代码

用Python直接获取各个主机Scrapy任务的运行状态了。

5.Scrapyrt提供一个调度的HTTP的接口,有了它我们不需要再执行Scrapy命令而是通过请求一个HTTP接口即可调度Scrapy任务。

pip3 install scrapyrt复制代码

爬虫基础

使用代理可以成功伪装IP地址,避免本机ip被因为单位时间请求次数过多被封。

代理分类

根据协议分类

FTP代理服务器
HTTP 代理服务器
SSL/TLS代理,主要用于访问加密网站
Telnet代理,主要用于Realplayer访问 Real流媒体服务器,一般有缓存功能,端口一般为554
POP3/SMTP代理 主要用于POP3/SMTP方式收发邮件,一般有缓存功能,端口一般为110/25
SOCKS代理,只是单纯传递数据包,不关心具体的协议和用法,一般端口为1080

基本库的使用

###urllib

使用urllib的request模块发起网络请求

import sslimport urllib.requestimport urllib.parsessl._create_default_https_context = ssl._create_unverified_contextdata = bytes(urllib.parse.urlencode({
'word': 'hello'}), encoding='utf8')response = urllib.request.urlopen('http://httpbin.org/post', data= data)print(response.read().decode('utf-8'))print(type(response))复制代码

在python3中需要import ssl这库。其中'

urlopen()只能发起简单的网络请求,如果需要设置更多的Header信息,需要用到Request

页面认证

有一些网页需要输入密码等信息才能查看页面内容,就需要认证,可以借助HTTPBasicAuthHandler完成认证

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_openerfrom  urllib.error import URLErrorusername = 'username'password = 'password'url = 'http://127.0.0.1:8000/06.%E7%9B%92%E5%AD%90%E6%A8%A1%E5%9E%8B.html'p = HTTPPasswordMgrWithDefaultRealm()p.add_password(None, url, username, password)auth_handler = HTTPBasicAuthHandler(p)opener = build_opener(auth_handler)try:    result = opener.open(url)    html = result.read().decode('utf-8')    print(html)except URLError as e:    print(e.reason)复制代码

分析robotparser协议

Robots协议也被称作爬虫协议、机器人协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,它通常有一个robots.txt的文本文件,放在网站的根目录下。

robots.txt的样例:

User-agent: * Disallow: /Allow: /public/复制代码

User-agent描述了搜索爬虫的名称;Disallow指定了不允许抓取的目录,上面的例子表示不允许抓取所有页面;Allow则是表示可以抓取的页面。

RobotParser模块提供了一个RobotFileParser,它可以根据某网站的robots.txt文件来判断一个爬取爬虫是否有权限来爬取这个网页。

抓取二进制数据

图片是二进制数据,是以bytes类型的数据

import requestsr = requests.get('https://github.com/favicon.ico')with open('favicon.ico', 'wb') as f:    f.write(r.content)复制代码

open()方法第一个参数是文件名,第二个参数是代表以二进制写的形式打开,可以向文件写入二进制数据并保存。

注释:需要搭建一个web框架,这里我直接用python 的框架库搭建了一个本地的服务器,用于本地的网络请求

python开发中有很多好的web框架,如Django、Tornado、Flask

Flask是一个面向简单需求小型应用的微框架。

Django包括一个开箱即用的ORM,全能型的web框架。 Tornado Facebook的开源异步web框架

我用Tornado搭建了一个web框架用于本地的网络请求,写了一个GET 和 POST 请求。

from tornado.web import Application, RequestHandler, urlfrom tornado.ioloop import IOLoopfrom tornado.httpserver import HTTPServerimport tornado.optionsimport jsontornado.options.define('port', default=9000, type=int, help='this is the port >for application ')class RegistHandler(RequestHandler):    """docstring for RegisterHandler"""    def initialize(self, title):        self.title = title    def set_default_headers(self):        self.set_header("Content-type", "application/json; charset=utf-8")        self.set_header("js", "zj")    def set_default_cookie(self):        self.set_cookie("loginuser", "admin")        print(self.get_cookie("loginuser"))    def get(self):        username = self.get_query_argument('username')        self.set_default_headers()        self.set_default_cookie()        self.write("{'简书':'知几'}")    def post(self):        self.set_default_headers()        # username = self.get_argument('username')        with open('app.json', 'r') as f:            data = json.load(f)            self.write(data)             if __name__ == '__main__':    # #创建一个应用对象    # app = tornado.web.Application([(r'/',IndexHandler)])    # #绑定一个监听端口    # app.listen(9000)    # #启动web程序,开始监听端口的连接    # tornado.ioloop.IOLoop.current().start()    app = Application(        [(r'/', IndexHandler),         (r'/regsit', RegistHandler, {
'title': '会员注册'})], debug=True) tornado.options.parse_command_line() http_server = HTTPServer(app) print(IOLoop.current()) # 最原始的方式 http_server.bind(tornado.options.options.port) http_server.start(1) # 启动Ioloop轮循监听 IOLoop.current().start()复制代码

会话维持

在Requests中直接使用get()或者post()等方法虽然能模拟网络请求,但是每次的请求相当于是不同的会话,即不同的Session。

import requestss = requests.Session()s.get('http://httpbin.org/cookies/set/number/123456789')r = s.get('http://httpbin.org/cookies')print(r.text)复制代码

利用Session可以做到模拟同一个会话,而且不用担心Cookies的问题。

###XPath解析库的使用

表达式 描述
nodename 选取此节点的所有子节点
/       | 从当前节点选取直接子节点   //      |从当前节点选取所有子孙节点   .       |选取当前节点   ..      |选取当前节点的父节点   @   | 选取属性复制代码
from lxml import etreehtml = etree.parse('/Users/Cathy/Desktop/test.html', etree.HTMLParser())result = html.xpath('//li/a')print(result)复制代码

如下有这个么一个test.html:

复制代码

获取其父节点,然后获取其class属性

from lxml import etreehtml = etree.parse('/Users/Cathy/Desktop/test.html', etree.HTMLParser())result = html.xpath('//a[@href="link4.html"]/../@class')print(result)复制代码

属性匹配

可以用@符号进行属性过滤,这里是选取class为Item-1的li节点。

from lxml import etreehtml = etree.parse('/Users/Cathy/Desktop/test.html', etree.HTMLParser())result = html.xpath('//li[@class="item-0"]')print(result)复制代码

匹配的结果又两个元素:

[
,
]复制代码

文本的获取

通过text()方法获取节点中的文本,这里的文本都在a中,如果直接通过li是获取不到文本的。

from lxml import etreehtml = etree.parse('/Users/Cathy/Desktop/test.html', etree.HTMLParser())result = html.xpath('//li[@class="item-0"]/a/text()')print(result)复制代码

PyQuery

html = '''
'''复制代码

初始化一个pyquery的对象,传入一个css的选择器,#container .list li的意思是选取id为container的节点内部的class为list的节点内部的所有li节点。

from pyquery import PyQuery as pqdoc = pq(html)li = doc('#container .list li')print(li)复制代码

查找节点也可以用find()方法 ,会将符合条件的所有节点选择出来。

from pyquery import PyQuery as pqdoc = pq(html)items = doc('.list')print(items.find('li'))复制代码

还提供了children() 、parent()等方法来获取某个节点的子节点和父节点。

获取信息

提取到节点之后,就是获取节点所包含的信息,如获取属性和文本。

###PyMySQL

mysql连接的时候需要额外指定一个db

import pymysql#建表db = pymysql.connect(host='localhost', user='root', password='123456', port=3306, db='spiders')cursor = db.cursor()sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, age INT NOT NULL, PRIMARY KEY (id))'cursor.execute(sql)db.close()复制代码

向表中插入数据

#插入数据id = '201200003'user = 'Wang'age = 11sql = 'INSERT INTO students(id, name, age) values(%s, %s, %s)'try:    cursor.execute(sql, (id, user, age))    db.commit()    print('ok')except:    db.rollback()     print('error')db.close()复制代码

如果发生异常,则rollback()执行数据回滚

# 查询数据sql = 'SELECT * FROM students'try:    cursor.execute(sql)    print('count:', cursor.rowcount) #获取数据查询结果的条数    one = cursor.fetchone() #获取第一条数据,偏移指针会指向下一条数据    print('one:', one)    results = cursor.fetchall()    print('results:', results)except:    print('error')复制代码

Ajax

Ajax就是Asynchronous JavaScript andXML ,即异步JavaScript和XMl。

Ajax 不是一门编程语言,而是利用 JavaScript 在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术

如下面链接 以getIndex开头的链接中 查看他的Headers,如果请求中会有一个信息为 X-Requested-With:XMLHttpRequest 这就代表着是Ajax.

在响应体里面返回了页面所有的渲染数据,JavaScript接收到这个数据之后,再执行渲染方法.

我们所看到的页面展示的数据并不是最原始的页面返回的,而是通过执行了JavaScript后再次向后台发送了Ajax请求,拿到数据进一步渲染,在Chrome查看网络请求的时候,可以通过XHR筛选出是Ajax的请求

Ajax结果提取
from urllib.parse import urlencodefrom pyquery import PyQueryimport requestsbase_url = 'https://m.weibo.cn/api/container/getIndex?'headers = {'Host': 'm.weibo.cn',    'Referer': 'https://m.weibo.cn/u/2145291155',    'User-Agent': 'Mozilla/5.0 (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': '2145291155',        'containerid': '1076032145291155',        'page': page    }    url = base_url + urlencode(params)    try:        response = requests.get(url=url,headers=headers)        if response.status_code == 200:            return response.json()    except requests.ConnectionError as e:        print('Error', e.args)def parse_page(json):    if json:        items = json.get('data').get('cards')        print(items)        for item in items:            item = item.get('mblog')            weibo = {}            weibo['id'] = item.get('id')            weibo['text'] = PyQuery(item.get('text')).text()            weibo['attitudes'] = item.get('attitudes_count')            weibo['comments'] = item.get('comments_count')            weibo['reposts'] = item.get('reposts_count')            yield weiboif __name__ == '__main__':    json = get_page(1)# 这个是页面数    results = parse_page(json)    for result in results:        print(result)复制代码

动态渲染页面抓取

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

selenium只能在 Chrome version must be between 70 and 73上使用,所以这里我们略过他

####二. Splash的使用 #####安装Splash Splash 是一个 JavaScript 渲染服务,是一个带有 HTTP API 的轻量级浏览器,同时它对接了 Python 中的 Twisted和 QT 库

启动Splash需要安装

拉取镜像

sudo docker pull scrapinghub/splash复制代码

启动容器,监控的端口为8050

docker run -p 8050:8050 scrapinghub/splash复制代码

打开就可以看到Splash的web页面。

Splash上默认的是http://google.com的地址,点击渲染,就能看到网页的返回结果呈现了渲染截图、HAR 加载统计数据、网页的源代码

我们能看到一段脚本:

function main(splash, args)  assert(splash:go(args.url))  assert(splash:wait(0.5))  return {    html = splash:html(),    png = splash:png(),    har = splash:har(),  }end复制代码

这个脚本是Lua语言写的脚本,这段代码的主要作用就是调用go() 方法去加载页面,返回了页面的源码、截图和HAR信息。

下面这段代码可以看到,通过evaljs()方法传入JavaScript的脚本,而document.title的执行结果就是返回网页的标题

function main(splash, args)  splash:go("http://www.baidu.com")  splash:wait(0.5)  local title = splash:evaljs("document.title")  return {title=title}end复制代码

####异步处理 Splash是支持异步处理的

function main(splash, args)  local example_urls = {
"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 resultsend复制代码

运行的结果是两个网站的截图

Splash的对象属性

main方法的中的第二个参数args相当于是splash.args属性

function main(splash, args)    local url = args.urlend复制代码
function main(splash)    local url = splash.args.urlend复制代码

#####js_enabled

这个属性是Splash的JavaScript的开关,true或者false来控制是否执行JavaScript代码。

#####resource_timeout

此属性可以设置加载的超时时间,单位是秒,如果设置为 0或 nil(类似 Python 中的 None)就代表不检测超时,我们用一个实例感受一下

function main(splash)    splash.resource_timeout = 0.1    assert(splash:go('https://www.taobao.com'))    return splash:png()end复制代码

#####go() go() 方法就是用来请求某个链接的方法,而且它可以模拟 GET 和 POST 请求,同时支持传入 Headers、Form Data 等数据。

#####jsfunc() 此方法可以直接调用 JavaScript 定义的方法,需要用双中括号包围,相当于实现了 JavaScript 方法到 Lua 脚本的转换。

#####evaljs() 可以执行 JavaScript 代码并返回最后一条语句的返回结果

####runjs() 此方法可以执行 JavaScript 代码,和evaljs的功能类似,但此方法更偏向于执行某一些动作或申明某些方法。而evaljs()更偏向获取执行某些结果。

function main(splash, args)  splash:go("https://www.baidu.com")  splash:runjs("foo = function() { return 'bar' }")  local result = splash:evaljs("foo()")  return resultend复制代码
autoload()

可以设置在每个页面访问时自动加载的对象

splash:autoload{source_or_url, source=nil, url=nil}复制代码

参数说明:

1.source_or_url,JavaScript 代码或者 JavaScript 库链接
2.source,JavaScript 代码。
3.url,JavaScript 库链接

此方法只是负责加载JavaScript代码或库,不执行任何操作,如果要执行操作可以调用evaljs() 或者runjs()方法

function main(splash, args)  splash:autoload([[    function get_document_title(){      return document.title;    }  ]])  splash:go("https://www.baidu.com")  return splash:evaljs("get_document_title()")end复制代码

####Splash API的调用 让Splash和Python程序结合使用并抓取JavaScript渲染的页面,Splash提供了一些HTTP接口,只需要请求这些接口并传递响应的参数即可获取页面渲染后的结果。

curl http://localhost:8050/render.html?url=https://www.baidu.com复制代码

用Python实现的话如下面代码:

import requestsurl = 'http://localhost:8050/render.html?url=https://www.baidu.com'response = requests.get(url)print(response.text)复制代码

转载于:https://juejin.im/post/5c8df55051882545c36ddea1

你可能感兴趣的文章
[Todo] Java并发编程学习
查看>>
Redis cluster学习 & Redis常识 & sort操作
查看>>
mysql 中实现多条数据同时更新
查看>>
2011 ACM/ICPC 成都赛区(为2013/10/20成都现场赛Fighting)
查看>>
Linux技术进阶示意图
查看>>
php设计模式课程---6、策略模式如何使用
查看>>
html5--6-8 CSS选择器5
查看>>
20145328 《信息安全系统设计基础》第6周学习总结
查看>>
python学习笔记:"爬虫+有道词典"实现一个简单的英译汉程序
查看>>
基于theano的深度卷积神经网络
查看>>
vCenter 部件关系简介 & 网络原理
查看>>
Mysql优化的方法
查看>>
Web.config或App.config中数据库链接路径的问题
查看>>
CPrintDialog 构造函数参数详解
查看>>
foreign key
查看>>
【二分答案】【字符串哈希】bzoj2084 [Poi2010]Antisymmetry
查看>>
Hbase 参数配置及优化
查看>>
看病要排队(stl)
查看>>
springMVC的controller返回值
查看>>
Httpclient与RestTemplate的比较(比httpClient更优雅的Restful URL访问)
查看>>