玩Python爬虫的必备知识清单
于2020-4-26重构
可以指明学习路线与方向
你需要知道的基本概念
通用爬虫:百度、谷歌搜索引擎
聚焦爬虫:根据特定需求,从特定网站爬取特定数据
爬虫工具:pycharm+anaconda+google chrome(其他浏览器也行)
http协议: 超文本传输协议, 是一种发布和接收HTML页面的方法
https协议:是http协议的加密版本,在http下加入了SSL层。服务器端口号是
443
端口与浏览器交互过程:
浏览器—>输入url-----get/post请求----->http服务器---->网站服务器----返回html---->http服务器---->用户浏览器【浏览器追加请求html引用的css、js、等动态文件】—…--->显示给用户
url:在浏览器中请求一个
url
,浏览器会对这个url进行一个编码。除英文字母,数字和部分符号外,其他的全部使用百分号+十六进制码值进行编码get请求: 只从服务器获取数据
post: 向服务器发送数据(登录)、上传文件等,会对服务器资源产生影响
爬虫时有反爬机制即强制要求用某种请求,具体爬虫时用哪种请求根据情况而定
谷歌抓包:
你需要掌握的库
urllib
基本介绍
最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据,在
Python3
的urllib
库中,所有和网络请求相关的方法,都被集到urllib.request库上urlopen函数
resp = request.urlopen('http://www.baidu.com') print(resp.read())
返回值
http.client.HTTPResponse 对象,故此用response做接收
urlretrieve函数
from urllib import request request.urlretrieve('http://www.baidu.com/','baidu1.html') #将目标网页保存到本地
urlencode函数
from urllib import parse data = {'name':'爬虫基础','greet':'hello world','age':100} qs = parse.urlencode(data) print(qs) #编码为Unicode格式发送
parse_qs函数
from urllib import parse qs = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100" #print(resp.read().decode("utf-8"))如果抓取时以utf-8进行编码传输,用utf-8解码没问题,否之不然,应先了解网页的编码方式,一般通过抓包查取 print(parse.parse_qs(qs))//解码经过编码的url
{‘name’: [‘爬虫基础’], ‘greet’: [‘hello world’], ‘age’: [‘100’]}
request.Request类
反反爬必备伪装技术
#模拟请求头User-Agent,爬虫程序更像个浏览器 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' } req = request.Request("http://www.baidu.com/",headers=headers) resp = request.urlopen(req) print(resp.read())
ProxyHandler处理器(代理设置)
为何使用:
固定某IP在某段时间内对网站服务器访问过多会被判定为非法访问,从而被限制或直接封掉opener与handler
如需使用代理ip,则替代urlopen方法,使用如下系列操作方法
handler = request.ProxyHandler({"http":"218.66.161.88:31769"}) opener = request.build_opener(handler) req = request.Request("http://httpbin.org/ip") resp = opener.open(req) print(resp.read())
寻找可用的ip:西刺代理,快代理,或代理云 + ip检测工具(匹配可用id)
request
此库重写urllib的大多方法,比之前的常规方法做了更进一步封装,并且做了拓展发送Get请求+
import requests response = requests.get("http://www.baidu.com/")
import requests kw = {'wd':'中国'} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode() response = requests.get("http://www.baidu.com/s", params = kw, headers = headers) # 查看响应内容,response.text 返回的是Unicode格式的数据,如果传过来的数据是经过gbk编码的话,对能获得我们要的文本 print(response.text) # 查看响应头部字符编码,可以方便我们利用decode针对解码 print(response.encoding)
发送POST请求
response = requests.post("http://www.baidu.com/",data=data)
import requests data = { 'first': 'true', 'pn': 1, 'kd': 'python' } resp = requests.post(url,headers=headers,data=data) # 如果是json数据,直接可以调用json方法 print(resp.json())
代理设置
在请求的方法中(例如
get
或者post
)传递proxies
参数就可以了import requests url = "http://httpbin.org/get" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36', } proxy = { 'http': '171.14.209.180:27829' } resp = requests.get(url,headers=headers,proxies=proxy) #保存为本地文件 with open('xx.html','w',encoding='utf-8') as fp: fp.write(resp.text)
共享曲奇饼(Cookie)
如果使用
requests
,要达到共享cookie
的目的,那么可以使用requests
库给我们提供的session
对象。以登录人人网为例,使用requests
来实现。示例代码如下:import requests url = "http://www.renren.com/PLogin.do" data = {"email":"email@qq.com",'password':"pythonspider"} headers = { 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36" } # 登录 session = requests.session() session.post(url,data=data,headers=headers) # 访问大鹏个人中心 resp = session.get('http://www.renren.com/880151247/profile') print(resp.text) #打印返回的Unicode文本
你需要掌握的数据解析
在从目标网站获得我们像要的数据后,我们需要从全站html中提取我们像要的数据,提取工具有(任选一种)
- XPath+lxml库(√)
- 美丽汤4(beautifulsoup4)
- 正则表达式(√)
xpath
xpath(XML路径语言)是一门在XML和HTML文档中查找信息的语言,可用于XML和HTML文档中对元素和属性进行遍历。
你应该知道的节点关系
<bookstore> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
以上,book为父,其中4个为子,4个互为同胞,bookstore为其中所有元素的先辈
同理bookstore其中所有元素又为其后代元素
例子
<?xml version="1.0" encoding="UTF-8"?> <bookstore> <book> <title lang="eng">Harry Potter</title> <price>29.99</price> </book> <book> <title lang="eng">Learning XML</title> <price>39.95</price></book></bookstore> </bookstore>
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下面列出了最有用的路径表达式:
表达式 描述 nodename 选取此节点的所有子节点。 / 从根节点选取。 // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 . 选取当前节点。 … 选取当前节点的父节点。 @ 选取属性。 在下面的表格中,列出了一些路径表达式以及表达式的结果:
bookstore 选取 bookstore 元素的所有子节点。 /bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。 //book 选取所有 book 子元素,而不管它们在文档中的位置。 bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 //@lang 选取名为 lang 的所有属性。 谓语
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 结果 /bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。 /bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。 /bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。 /bookstore/book[position()<‘'3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 //title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。 //title[@lang=‘eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 /bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 /bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
正则表达式
你需要掌握的数据存储
经过爬取,解析,接下来我们要将我们想要的数据存储下来,我们有以下几种选择方案
- json(简单好用,强烈推荐)
- csv
- excel
- mysql(需要数据库基础)
- mongoDB(需要数据库基础)
JSON
理想的数据交换语言,易于人阅读和编写,同时也易于机器解析和生成 , 并有效地提升网络传输效率 ,本质就是字符串
JSON在python中支持的数据类型
- 对象(字典)。使用{}。
- 数组(列表)。使用[]。
- 整形、浮点型、布尔类型还有null类型。
- 字符串类型(字符串必须要用双引号,不能用单引号)。
字典(对象)和列表(数组)转为JSON格式
使用json.dumps方法
import json books = [ { 'title': '钢铁是怎样练成的', 'price': 9.8 }, { 'title': '红楼梦', 'price': 9.9 } ] json_str = json.dumps(books,ensure_ascii=False) print(json_str)
因为
json
在dump
的时候,只能存放ascii
的字符,因此会将中文进行转义,这时候我们可以使用ensure_ascii=False
关闭这个特性。
在Python
中。只有基本数据类型才能转换成JSON
格式的字符串。也即:int
、float
、str
、list
、dict
、tuple
。将JSON字符串dump到文件中
json
模块中除了dumps
函数,还有一个dump
函数,这个函数可以传入一个文件指针,直接将字符串dump
到文件中。示例代码如下:import json books = [ { 'title': '钢铁是怎样练成的', 'price': 9.8 }, { 'title': '红楼梦', 'price': 9.9 } ] with open('a.json','w') as fp: json.dump(books,fp) # a.json代表文件名 w代表以写的方式打开
json字符串转化成Python对象
使用json.load方法
import json json_str = '[{"title": "钢铁是怎样练成的", "price": 9.8}, {"title": "红楼梦", "price": 9.9}]' books = json.loads(json_str,encoding='utf-8') print(type(books)) print(books)
第一个打印输出结果为list列表类型
直接从文件中读取json并转化为python对象:
import json with open('a.json','r',encoding='utf-8') as fp: json_str = json.load(fp) print(json_str)