通过网课和万能的B站学习 Python 和爬虫(本文基本是对视频内程序和内容的笔记内容)
Python 学习网络爬虫主要分3个大的版块:明确目标,抓取,分析,存储
- 明确目标 (要知道你准备在哪个范围或者网站去搜索)
- 爬 (将所有的网站的内容全部爬下来)
- 取 (去掉对我们没用处的数据)
- 处理数据(按照我们想要的方式存储和使用)
网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定 url ,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
用Python写爬虫的理由
代码简洁,开发的效率高,模块丰富(相关的 HTTP 请求模块和 HTML 解析模块),许多爬虫框架(Scrapy)
工具:
- Python 3.X开发环境
- Pycharm
urllib库
Python中一个基本的网络请求库,可以模拟浏览器的行为
urlopen的用法
对urlopen的详解:
- url:请求的 url 。
- data:请求的 data ,如果设置了这个值,那将变成post请求
- 返回值:有 read()(读取所有数据)、read(size)(读取size大小的数据)、readline()(读取第一行的数据)、readlines()(读取多行,将返回的值以多行形式显示出来)
PS:常见的请求方式:
- get 请求:一般情况下,只从服务器获取数据,不会对服务器资源产生任何影响
- post 请求:向服务器发送数据(登陆)、上传文件等,会对服务器资源产生影响
urlopen的基本使用:
from urllib import request
resp = request.urlopen('http://www.baidu.com/')
print(resp.read())
以上三行代码将我们输入的url(http://www.baidu.com/) 的所有代码爬下来了
urlretrieve函数
这个函数可以将网页上的文件保存到本地
比如在百度图片上搜索s1mple(在 ?为什么会混入一只Guardian)
我们将一张图片的地址复制下来 例如(https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1984368275,3349832842&fm=26&gp=0.jpg)
from urllib import request
request.urlretrieve('https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1984368275,3349832842&fm=26&gp=0.jpg','top1.jpg')
运行代码后发现TOP1的图片已经被下载下来
urlencode函数和parse_qs函数
用浏览器发送请求的时候,如果 url 中包含了中文或者其他的特殊字符,那么浏览器会自动给我们进行编码。但是如果通过代码发送,就需要我们手动进行编码,此时可以使用urlencode 函数来实现。urlencode 函数可以把字典数据转换为 url 编码的数据。同时,我们也可以用 parse_qs 函数将经过编码后的 url 参数进行解码
PS:在浏览器中请求一个 url,浏览器会对这个 url 进行一个编码。除英文字母,数字和部分符号外,其他的全部使用百分号+十六进制码值进行编码
from urllib import request, parse
url = 'http://www.baidu.com/s?'
params = {"wd": 'ESL科隆'}
qs = parse.urlencode(params) #运用urlencode函数将ESL科隆进行编码
#url = url + "?" + qs
print(qs) #输出qs为 wd=ESL%E7%A7%91%E9%9A%86
qs1 = parse.parse_qs(qs) #运用parse_qs进行解码
print(qs1) #输出qs1为 {'wd': ['ESL科隆']}
#resp = request.urlopen(url)
#print(resp.read())
urlparse函数和urlsplit函数
有时我们需要对url中的各个部分进行分割,那么这时候就需要使用 urlparse 或 urlsplit 函数来进行分割(urlparse 和 urlsplit 函数使用基本相同)
PS:url 详解
url 由一下几个部分组成:
scheme://host:port/path/?query-string=xxx#anchor
名称 | 意义 |
---|---|
scheme | 代表的是访问的协议,一般为 http 或 https 或 ftp 等 |
host | 主机名,域名。比如 www.baidu.com |
port | 端口号。当你访问一个网站的时候,浏览器默认使用80端口(http 协议使用80端口,https 协议使用443端口) |
path | 查找路径。比如:www.jianshu.com/trending/now ,后面的 trending/now 就是 path |
query-string | 查询字符串,比如:www.baidu.com/s?wd=s1mple ,后面的 wd=s1mple 就是查询字符串 |
anchor | 锚点,后台一般不用管,前端用来做页面定位的 |
from urllib import request, parse
url = 'http://www.baidu.com/s?wd=python&username=abc#1'
result = parse.urlparse(url)
print(result)
结果如下图所示
我们也可以分部分输出
from urllib import request, parse
url = 'http://www.baidu.com/s?wd=python&username=abc#1'
result = parse.urlparse(url)
print('scheme:', result.scheme)
print('netloc:', result.netloc)
print('path:', result.path)
print('params:', result.params)
print('query:', result.query)
print('fragment:', result.fragment)
结果如下图所示
urlparse函数和urlsplit函数区别: urlsplit函数分割的url里没有params这个属性
request.Request 类
如果想要在请求的时候加一些请求头,就需要使用 request.Request
例如在访问拉钩网时,因为拉钩网有采用反爬,所以单纯用 urlopen 只会返回给你一串很短的数据
from urllib import request, parse
url = 'https://www.lagou.com/jobs/list_python?l'
resp = request.urlopen(url)
print(resp.read())
使用 request.Request 类给请求一个 User-Agent 才能正常返回数据
from urllib import request, parse
url = 'https://www.lagou.com/jobs/list_python?l'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
req = request.Request(url, headers=headers) #此时并没有真正的发送出去
resp = request.urlopen(req)
print(resp.read())
爬取职位信息
from urllib import request, parse
#url = 'https://www.lagou.com/jobs/list_python?l'
url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
data = {
'first':'true',
'pn': 1,
'kd': 'python'
}
req = request.Request(url, headers=headers, data=parse.urlencode(data).encode('utf-8'), method= 'POST') #此时并没有真正的发送出去
resp = request.urlopen(req)
print(resp.read().decode('utf-8')) #用decode函数进行解码
但是被网站识别出来,显示操作太频繁。需要伪造更多地信息
加了更多地 Header 信息还是进不去 铁憨憨实锤了
from urllib import request, parse
#url = 'https://www.lagou.com/jobs/list_python?l'
url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
'Referer':'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
'Cookie':'JSESSIONID=ABAAABAAAFCAAEGFFB1AF30B558E375F456FF87214E9213; _ga=GA1.2.69043083.1563435058; user_trace_token=20190718153058-fc2fcec1-a92d-11e9-80b7-525400f775ce; LGUID=20190718153058-fc2fd280-a92d-11e9-80b7-525400f775ce; _gid=GA1.2.1622069834.1563435059; index_location_city=%E5%85%A8%E5%9B%BD; _gat=1; LGSID=20190719093221-0dac1782-a9c5-11e9-80ed-525400f775ce; PRE_UTM=; PRE_HOST=www.baidu.com; PRE_SITE=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DIineWIw_nK3VojGpeWhUHlig5kesFBaJUi7NgojGMLS%26wd%3D%26eqid%3D98e658ad003ff02a000000045d311da1; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1563435059,1563499943; TG-TRACK-CODE=index_search; X_HTTP_TOKEN=5be5e7fc203cd1157499943651d0ab41993d472ff2; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1563499949; LGRID=20190719093227-117f8bcb-a9c5-11e9-a4e9-5254005c3644; SEARCH_ID=d4b318ca806d45b5bbec2fcf2ad16dd0',
'X-Anit-Forge-Code': 0,
'X-Anit-Forge-Token': 'None',
'X-Requested-With': 'XMLHttpRequest'
}
data = {
'first':'true',
'pn': 1,
'kd': 'python'
}
req = request.Request(url, headers=headers, data=parse.urlencode(data).encode('utf-8'), method= 'POST') #此时并没有真正的发送出去
resp = request.urlopen(req)
print(resp.read().decode('utf-8'))