爬虫笔记整理2 - 基本库的使用总结

3.1 使用urllib

to be continued

3.2 使用requests(重点)

Requests库学习

一、requests介绍

基于urllib3的一个爬虫库,目前最完善,简单,稳定,好用的库

二、requests用法

1、get、head、options、delete等

r = requests.get('http://httpbin.org/') # head, option等
print(r.text)

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.text)

payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.text)

2、post

headers = {
    'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  r'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3',
    'Referer': r'http://httpbin.org',
    'Connection': 'keep-alive'
}
data = {
	    'key1': 'value1',
	    'key2': 'value2'
	}
url = 'http://httpbin.org/post'
r = requests.post(url, data=data, headers=headers)
print(r.text)

print(r.json())

#支持json
import json
r = requests.post(url, data=json.dumps(data), headers=headers) 
# 字符串转json: json.loads(string)
# dump和load 都是操作文件

3、编码

r.content 返回的是bytes,需要自己根据需求进行编码转换
r.text 是根据判断的编码转换后的str

判断方法如下:

requests.adapters模块下 HTTPAdapter 类中的 build_response 方法:
response.encoding = get_encoding_from_headers(response.headers)
跳转到requests.utils模块的 get_encoding_from_headers 方法:

content_type = headers.get(‘content-type’) # 值为:text/html
if ‘text’ in content_type:
return ‘ISO-8859-1’
所以结论是这个 ISO-8859-1 的意义就是r.text的默认编码
如果response.encoding为None,就使用 chardet.detect(self.content)[‘encoding’] 判断出编码,一般是 utf-8

r = requests.get('http://www.baidu.com')
print(r.encoding)

content = r.content
print(content)
print(content.decode('utf-8'))

print(r.text)
text = r.text
print(text.encode('raw_unicode_escape').decode('utf-8'))
print(text.encode('iso-8859-1').decode('utf-8'))
print(text.encode(r.encoding).decode('utf-8')) # 有可能为None,这样不保险

编码解码 参数errors:

  • 默认的参数就是strict,代表遇到非法字符时抛出异常;

  • 如果设置为ignore,则会忽略非法字符;

  • 如果设置为replace,则会用?取代非法字符;

  • 如果设置为xmlcharrefreplace,则使用XML的字符引用。
    s = ‘我是测试中文abc123’
    print(s.encode(‘ascii’, ‘ignore’))
    print(s.encode(‘ascii’, ‘replace’))
    print(s.encode(‘ascii’, ‘xmlcharrefreplace’))

    s = ‘我是测试中文abc123’
    s_ascii = s.encode(‘ascii’, ‘xmlcharrefreplace’)
    print(s_ascii.decode(‘ascii’))
    from common.util import xmlchar_2_cn
    print(xmlchar_2_cn(s_ascii.decode(‘ascii’)))

4、响应状态码

r = requests.get('http://httpbin.org/') # head, option等
if r.status_code == requests.codes.ok:
if r.status_code == 200:
	print('成功')
else:
	print('失败')

5、 cookie

  • path区分大小写,应与浏览器中的地址栏的输入一致
  • path不可读,只可写
  • path不可更改,试图更改,其实是新写另一个cookie
  • path和domain都有继承性,子目录可以读父目录的cookie,二级域名也能读取一级域名的cookie
    jar = RequestsCookieJar()
    jar.set(‘tasty_cookie’, ‘yum’, domain=‘httpbin.org’, path=’/cookies’)
    jar.set(‘gross_cookie’, ‘blech’, domain=‘httpbin.org’, path=’/elsewhere’)
    jar.set(‘root_cookie’, ‘root’, path=’/’)
    jar.set(‘default_cookie’, ‘default’)
    url = ‘http://httpbin.org/cookies’
    r = requests.get(url, cookies=jar)
    print(r.text)

6、重定向

r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code)

7、超时

r = requests.get('http://httpbin.org/', timeout=0.001)
print(r.status_code)

8、代理

proxies = {'http': '127.0.0.1:8888'}
r = requests.get('http://httpbin.org/', proxies=proxies)
print(r.status_code)

9、https

出现SSLError(“bad handshake: Error([(‘SSL routines’, ‘tls_process_server_certificate’, ‘certificate verify failed’)],)”,)错误
r = requests.get(‘https://www.alipay.com’, verify=False)
print(r.status_code)

10、一般更多使用session,不直接使用request.get()

s = requests.session()
r = s.get('http://httpbin.org/')
print(r.status_code)

11、多线程

'''
    多线程
'''
import threading

from time import ctime

def request_httpbin(num=0, url='http://httpbin.org/'):
    print('第 %s 次请求 开始, %s' % (num, ctime()))
    r = requests.get('http://httpbin.org/')
    print('第 %s 次请求 结束, %s' % (num, ctime()))

if __name__ == '__main__':
    threads = []
    for i in range(1, 101):
        t = threading.Thread(target=request_httpbin, args=(i,))
        threads.append(t)

    for t in threads:
        t.start()

    for t in threads:
        t.join()

12、使用gevent实现并发

'''
使用gevent实现并发
'''
import requests
import gevent
import urllib3
urllib3.disable_warnings()
import time
from gevent import monkey
monkey.patch_all()

urls = [
    'https://docs.python.org/2.7/library/index.html',
    'https://docs.python.org/2.7/library/dl.html',
    'http://www.iciba.com/partial',
    'http://2489843.blog.51cto.com/2479843/1407808',
    'http://blog.csdn.net/woshiaotian/article/details/61027814',
    'https://docs.python.org/2.7/library/unix.html',
    'http://2489843.blog.51cto.com/2479843/1386820',
    'http://www.bazhuayu.com/tutorial/extract_loop_url.aspx?t=0',
]

def method1():
    t1 = time.time()
    for url in urls:
        res = requests.get(url, verify=False)

    t2 = time.time()
    print('method1', t2 - t1)

def method2():
    jobs = [gevent.spawn(requests.get, url, verify=False) for url in urls]
    t1 = time.time()
    gevent.joinall(jobs)
    t2 = time.time()
    print('method2', t2 - t1)

if __name__ == '__main__':
    method1()
    method2()

三、grequests库用法

是一个基于request和gevent的库

import time
import requests
import grequests
import urllib3
urllib3.disable_warnings()

urls = [
    'https://docs.python.org/2.7/library/index.html',
    'https://docs.python.org/2.7/library/dl.html',
    'http://www.iciba.com/partial',
    'http://2489843.blog.51cto.com/2479843/1407808',
    'http://blog.csdn.net/woshiaotian/article/details/61027814',
    'https://docs.python.org/2.7/library/unix.html',
    'http://2489843.blog.51cto.com/2479843/1386820',
    'http://www.bazhuayu.com/tutorial/extract_loop_url.aspx?t=0',
]

def method1():
    t1 = time.time()
    for url in urls:
        res = requests.get(url, verify=False)

    t2 = time.time()
    print('method1', t2 - t1)

def method2():
    tasks = [grequests.get(u) for u in urls]
    t1 = time.time()
    res = grequests.map(tasks, size=3)
    t2 = time.time()
    print('method2', t2 - t1)

def method3():
    tasks = [grequests.get(u) for u in urls]
    t1 = time.time()
    res = grequests.map(tasks, size=8)
    t2 = time.time()
    print('method3', t2 - t1)

def method4():
    tasks = [grequests.get(u, callback=response_handle) for u in urls]
    t1 = time.time()
    res = grequests.map(tasks, size=8)
    t2 = time.time()
    print('method3', t2 - t1)

def response_handle(r, *args, **kwargs):
    print(r.url)

if __name__ == '__main__':
    method1()
    method2()
    method3()
    method4()

课堂笔记:

1、2个列表的遍历合并

建议使用 zip
li6 = [(x, y) for x, y in zip(li1, li2)]

2、request 中的 method

必须大写!!

3、requests库中

get 方法 是发送 get请求
post 方法 是 发送post请求

response.text : 获取响应的str
response.content:  获取响应的 bytes
response.url  :  获取响应的 url地址
response.json() :  如果 response的返回值是 json字符串 那么调用 json() 即可直接得到 字典对象

4、 requests库 get 请求

传递url参数
通过 ?
url = 'http://www.baidu.com/s?word=python'
response = requests.get(url)

通过 params参数
url = 'http://www.baidu.com/s'
params = {
    'word': 'python'
}
response = requests.get(url, params=params)

不同的情况使用不同的方式:
?    :  固定值、参数个数很少
params: 参数值是动态传入的、参数个数比较多

5、 requests库的 post 方法

参数
data:  提交form表单, http传递的数据是  key=value&key1=value1 的格式

json: 提交json字符串

两者不能同时存在!!!!!!!

但是  post 的参数 和  url参数是可以共存的!!!

6、requests 库 post请求的参数

必须:
url :  网页地址

常用:
params:  url参数
data:   form表单参数    和其他 请求体 相斥
json:  json字符串参数   和其他 请求体 相斥
headers:  请求头的字典
proxies: 设置代理  {'http': '127.0.0.1:8888', 'https': '127.0.0.1:8888'}
verify:  当访问 https 网站,是否效验服务器的证书, 一般都设置为 False

不常用
cookies:  手动指定 cookie 对象
files:   文件参数  和其他 请求体 相斥
allow_redirects:  布尔型, 是否自动跳转, 对应 3XX 状态码

不使用的:
auth:  http验证,不使用
timeout: 超时时间
stream:  是流模式还是立即下载
cert:  证书文件所在位置

7、 301和302 状态码

通知 客户端, 当前url的功能已经转移到另一个url
这个url会在
response的 headers中的 Location 指出

如果是手动处理的话:
1、访问 url1
2、服务器返回 response, 状态码是 302
3、提取 response 的 headers 中的 Location 中的value , 得到下一个 url2
4、继续访问 url2
5、如果 返回值依然是 302或301,那么重复第3、4步
6、直到返回的 状态是 200 或其他 4XX 或 5XX


浏览器会自动获取这个 location, 并且再次发起 访问
requests库,通过设置  allow_redirects = True, 也会自动处理 302和301

也就是说:
使用requests库时,只要设置了  allow_redirects = True , 那么所有的 301和302 都会自动处理
那么不管是连续多少个 302
我们只需要处理2个对象
https://passport.lagou.com/grantServiceTicket/grant.html	302
http://www.lagou.com/?action=grantST&ticket=ST-9e5ceab760454b76900302173ba57d84	302
https://www.lagou.com/?action=grantST&ticket=ST-9e5ceab760454b76900302173ba57d84	302
http://www.lagou.com/	302
https://www.lagou.com/	200
1、 第一个 302 的 url, 需要我们手动发起访问
    response = reqeusts.get('https://passport.lagou.com/grantServiceTicket/grant.html')
2、我们得到的 response 是 最后一个 非 3XX 的状态码的 响应
    即 得到的是 https://www.lagou.com/	200  这个请求的 response


注意: 302和301 都只会出现 get 请求

8、 response 的 字符集

response.encoding  获取,也可以设置
response.content # 得到 bytes
response.text # 得到 文本 ,  这个文本其实就是通过 response.content.decode(response.encoding) 获取的

如果 response.text  出现乱码
解决方案:
通过手动设置 response.encoding = 'utf-8'
一般都可以解决, 还有部分需要设置为 gbk :  response.encoding = 'gbk'

可以查看 html 页面中的

里面的 charset

9、 debug 调试

step over:  单步执行, 指定当前行, 断点行移动下一行代码上
step into:  单步进入, 进入当前行的第一个未执行的函数
step out:   单步退出, 退出当前函数,回到调用该函数的代码行
Resume Program:  执行整个程序到下一个断点

10、在 pycharm中 调试时,碰到如下代码块:

    def decode(self, *args, **kwargs): # real signature unknown
        """
        Decode the bytes using the codec registered for encoding.

          encoding
            The encoding with which to decode the bytes.
          errors
            The error handling scheme to use for the handling of decoding errors.
            The default is 'strict' meaning that decoding errors raise a
            UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
            as well as any other name registered with codecs.register_error that
            can handle UnicodeDecodeErrors.
        """
        pass

就表明该函数是 由  C语言 实现的!
而当前我们看到的函数、参数、文档注释、pass 都是由  pycharm 根据 C语言 中  decode 函数的  文档注释,
模拟展示出来的,真实的python代码中是没有这个函数的!!!

11、 response 的 encoding 是由什么决定的?

查看 requests 的  utils.py 模块中 get_encoding_from_headers  函数
4 种情况
1、判断response 的headers中 是否有 content-type  ,
    如果不存在,那么返回 None
如果存在,那么继续往下判断:
2、 如果 content-type 中是类似这样: application/json;charset=UTF-8
    那么返回 charset的 value: UTF-8
3、response的headers 中 存在 content-type,但是value中没有 charset,包含 text
    那么返回 iso-8859-1
4、上述都不满足,返回 None

4种情况,但是只有3种结果:
1、None :  调用 chardet.detect(self.content)['encoding']  猜测 编码集
2、headers中的content-type中指定的 charset
3、iso-8859-1

12、chardet.detect(self.content)[‘encoding’]

根据 self.content 中的bytes , 判断 最适合的 编码集
根据一些规则,直接进行 字符集的匹配, 如果匹配对应的规则,则返回 字符集, 什么规则都不匹配
那么就进行转码尝试, 不报错的即选择

13、代理错误:

requests.exceptions.ProxyError: HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url:

原因:程序开启了代理设置,但是对应的代理IP和端口并没有开启
解决:1、不使用代理
      2、开启对应的代理软件

14、警告信息:

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

InsecureRequestWarning)

解决:
import urllib3

urllib3.disable_warnings()

项目:登录GitHub

1、登录 github
登录首页:https://github.com/login
实现 github的登录,

补充题:
搜索指定的 项目名, 譬如 cpython


注意:没有账号的都去注册一个
    注册地址: https://github.com/join?source=login

    账号: mumuloveshine
    密码: mumu2018

“”"第2章request库

  1. request的简单实用
  2. request的深入使用

“”"

# 2.1. request的简单实用

# 1. request的简单实用
"""1. request的简单实用
why学request
request库是基于urllib3的一个爬虫库,目前最完善,简单,稳定,好用的库
requests的底层实现就是urllib
requests在python2 和python3中通用,方法完全一样
requests简单易用
Requests能够自动帮助我们解压(gzip压缩的等)网页内容


如何学?
中文API: http://docs.python-requests.org/zh_CN/latest/index.html
英文API: http://docs.python-requests.org/en/master/

快速上手:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html#id2

"""

# 2.response.text 和response.content的区别
"""
response.text 和response.content的区别?
response.text
类型:str
解码类型: 根据HTTP 头部对响应的编码作出有根据的推测,推测的文本编码
如何修改编码方式:response.encoding=”gbk”

response.content
类型:bytes
解码类型: 没有指定
如何修改编码方式:response.content.deocde(“utf8”)

更推荐使用response.content.deocde()的方式获取响应的html页面




import requests
response = requests.get('http://www.baidu.com')
# print(response)
# 
# print(response.text)

# requests按照哪种编码的?
# print(response.encoding) # ISO-8859-1

#然后用text解码,失败
# 那么我们按照指定的编码方式解码
#
response.encoding = 'utf-8'
print(response.encoding)
# print(response.text)

# print(response.content) # 区别返回结果二进制 bytes类型(因为原汁原味,更已操作,推荐)
print(response.content.decode()) # 返回结果bytes类型
# decode默认不写,是utf-8

#总结 requests中解决编解码的方法
# - response.content.decode()
# - response.content.decode("gbk")
# - response.text

"""

# 3.实例应用,保存图片到本地

"""实例应用,保存图片到本地:
import requests

url = 'http://docs.python-requests.org/en/master/_static/requests-sidebar.png'

response = requests.get(url)
# 文件名,打开方式,写二进制
with open('pic.jpg','wb') as f:
    f.write(response.content)
# 写入的时二进制用content
"""

# 4. 判断请求是否成功?

"""判断请求是否成功?
import requests

response = requests.get('https://www.baidu.com')
# status_code = response.status_code
# print(response.status_code)
# 200 请求成功
# 如果不是200,请求失败
# 200请求某个url地址,响应成功,而不是我们想要访问的url地址,eg.比如我们请求一个登陆之后才能访问,200但不代表我们成功

# 所以判断请求是否成功?
assert response.status_code == 200 # 断言,假设它是200,成功没问题
assert response.status_code == 300 # 断言,假设它是300,失败

# 所以定义一个方法,专门判断请求是否陈宫,后续讲到
"""

# 5. 响应头
"""响应头

import requests

response = requests.get('https://www.baidu.com')

# 关注响应头,只关注set-cookie这一块
# print(response.headers)

# {'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform',
#  'Connection': 'Keep-Alive', 'Content-Encoding': 'gzip', 'Content-Type': 'text/h
# tml', 'Date': 'Sun, 02 Dec 2018 16:32:41 GMT', 'Last-Modified': 'Mon, 23 Jan 201
# 7 13:23:51 GMT', 'Pragma': 'no-cache', 'Server': 'bfe/1.0.8.18', ' \
#                                                               ''Set-Cookie': '
# BDORZ=27315; max-age=86400; domain=.baidu.com; path=/', 'Transfer-Encoding': 'ch
# unked'}
"""

# 6. 请求头
"""请求头,引出如何发送带header的请求

import requests

response = requests.get('https://www.baidu.com')

print(response.request.url)

print(response.url)

# 服务器定义到另一个url地址的时候

print(response.request.headers)
# {'User-Agent': 'python-requests/2.20.1', 'Accept-Encoding': 'gzip, deflate', 'Ac
# cept': '*/*', 'Connection': 'keep-alive'}
# 这是默认的请求头,肯定有问题,判断出来是怕从

# 还有一个问题:我们response返回的内容只有一点,但html源码里面的代码很多,问题时是因为我们没有设置user-agent,没有模拟浏览器
# 所以服务器知道我们不是一个正规的刘篮球或者不是浏览器

"""

# 7. 发送带header的请求
"""发送带header的请求,如何模拟?

# why,上一个问题解决了。真正做到欺骗浏览器,获取和浏览器一直的内容

import requests

# 通常我们只需要添加一个user-agent就行了,如果还不行,我们就得加上cookie,大部分情况都是可以的
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"}
response = requests.get('https://www.baidu.com',headers = headers)
print(response.content.decode())

# 注意内容看上去是有很多空格,其实是有 \n \r换行 空格 \t制表符的
"""

# 8. 发送带参数的请求
"""发送带参数的请求

import requests
# url = 'https://www.baidu.com/s?' # 加不加问好无所谓,request起到的作用其实就是拼接
# 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"}
# kw = {'wd':'美国'}
# response = requests.get(url, headers = headers, params = kw)# 最后参数设置指定顺序,
# print(response.status_code)
# print(response.url)

url = 'https://www.baidu.com/s?wd={}'.format('美国')  # 加不加问好无所谓,request起到的作用其实就是拼接
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"}
response = requests.get(url, headers = headers)# 最后参数设置指定顺序,
print(response.status_code)
print(response.url)

# 注意:url是有专门的编码解码,用站长工具—— http://tool.chinaz.com/Tools/urlencode.aspx
# https://www.baidu.com/s?wd=美国  对应 https://www.baidu.com/s?wd=%E7%BE%8E%E5%9B%BD

"""

# 实例应用 1、获取新浪首页,查看response.text 和response.content.decode()的区别
"""
# 实例应用 1、获取新浪首页,查看response.text 和response.content.decode()的区别

import requests
url = 'https://www.sina.com.cn'
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"}
r = requests.get(url, headers = headers)
print(r.text)
print('*'*1000)
print(r.content.decode())
# print(r.status_code)
"""

# 实例应用2、实现任意贴吧的爬虫,保存网页到本地
"""实例应用2、实现任意贴吧的爬虫,保存网页到本地

import requests

# 自己的老方法
# url = 'https://tieba.baidu.com'
# # url = 'https://www.tieba.baidu.com' # 奇怪,加www就搞不定
# 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"}
# r = requests.get(url, headers = headers)
# print('*'*1000)
# print(r.content.decode())
# print(r.status_code)


# 1.构造url列表
# 2.遍历,发送请求,获取响应
# 3.保存



# 定义个类
class TiebaSpider:
    # 传一个参数过来,目的就是实例化tiebaspider时候,给它传参数
    def __init__(self, tieba_name):
        # 第一页的url地址放到这里来,需要输入的参数格式化
        # self.url_temp = 'https://tieba.baidu.com/f?kw=公务员&pn={}'
        self.tieba_name = tieba_name
        self.url_temp = 'https://tieba.baidu.com/f?kw='+tieba_name+'&ie=utf-8&pn={}'
        self.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"}


    def get_url_list(self):
        url_list = []
        for i in range(1000):
            url_list.append(self.url_temp.format(i*50)) # 第一页是0   50
        return url_list

    # 发送请求,获取响应;单独作为一个方法
    # url
    def parse_url(self,url):
        response = requests.get(url, headers = self.headers)
        return response.content.decode()

    # 页码数,没有,就需要我们传一个参数
    def save_html(self,html_str, page_num):

        # 需要名字不一样
        file_path = '{}-第{}页.html'.format(self.tieba_name,page_num)
        with open(file_path, 'w',encoding='utf-8') as f:
            f.write(html_str)
            # ascii codec can't encode characters in ordinal not in range,需要加encoding = utf-8

# 实现主要逻辑
    def run(self):
        url_list = self.get_url_list()
        # 遍历,获取响应
        for url in url_list:
            html_str = self.parse_url(url)
            # 保存
            page_num = url_list.index(url)+1 # 页码数
            self.save_html(html_str, page_num)


# 第一个问题:main的右半边没有了
if __name__ == '__main__':
    tieba_spider1 = TiebaSpider('lol')
    tieba_spider1.run()
    
    
# 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。
# 
# if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
"""


# 2.2 request的深入使用
"""2.2 request的深入使用

1 发送post请求
2 使用代理
3 处理 cookies session

"""

# 1. 发送post请求 概念
"""2.1 发送post请求 概念
哪些地方我们会用到POST请求:

1. 登录注册( POST 比 GET 更安全)

2. 需要传输大文本内容的时候( POST 请求对数据长度没有要求)


所以同样的,我们的爬虫也需要在这两个地方回去模拟浏览器发送post请求

"""
# 发送post请求,实例应用
"""发送post请求,实例应用

eg. 百度翻译

区别:有from data:
query=hello

response是:
{"error":0,"msg":"success","lan":"en"}

接触到json数据,json数据如何格式化?

1. atom : pretty-json
https://segmentfault.com/a/1190000008141401
2. notepad++
3. 在线json格式化
4. pycharm格式化,需要专门建一个json文件



from data:

from: en
to: zh
query: hello
simple_means_flag: 3
sign: 54706.276099
token: f7a1bf54c701f8883f2223b3142f550f

对比

from: en
to: zh
query: kiss
transtype: translang
simple_means_flag: 3
sign: 479956.242149
token: f7a1bf54c701f8883f2223b3142f550f

"""

# 实例应用:通过百度翻译,实现一个翻译工具
"""实例应用:通过百度翻译,实现一个翻译工具

import requests
url = 'https://fanyi.baidu.com/v2transapi'
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"}
data = {
    'to':' zh',
    'query': 'kiss',
    'transtype': 'translang',
    'simple_means_flag': '3',
    'sign': '479956.242149',   # 分析后是用js生成的
    'token': 'f7a1bf54c701f8883f2223b3142f550f' # crtl+f 在elements中
}
# 注意:变字典的过程中学到了快捷键的设置

# to: zh
# query: kiss
# transtype: translang
# simple_means_flag: 3
# sign: 479956.242149
# token: f7a1bf54c701f8883f2223b3142f550f
# v2transapi	v2transapi	v2transapi	v2transapi	v2transapi	v2transapi	v2transapi


r = requests.post(url, headers = headers, data = data)
print(r.content.decode())
# {"error":997,"from":null,"to":" zh","query":"kiss"}

# 怎么办?有error了,这条路走不通


"""

# 高级改进
"""高级改进
import requests, json, sys # 复习一下命令行参数

# print(sys.argv)
# ['D:/TOTAL 1 PYTHON/PYCHARM/REXUE/craw_study_total/craw_heima/day1note.py']


query_string = sys.argv[1]
# 列表
# ['D:/TOTAL 1 PYTHON/PYCHARM/REXUE/craw_study_total/craw_heima/day1note.py']

url = 'https://fanyi.baidu.com/basetrans'
headers = {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'}
data = {
    # 'query': '人生苦短,我用python',
    'query': query_string,
    'from': 'zh',
    'to': 'en'
}

r = requests.post(url, headers = headers, data = data)
# print(r.content.decode())

# 注意:范了两次错: 掉了user-agent,没有写成json格式

# 然后我们要把结果取出来

dict_ret = json.loads(r.content.decode())
ret = dict_ret['trans'][0]['dst']     # 首先,是字典,其次是列表,最后再是字典
print('result is :', ret)

{"errno":0,"from":"zh","to":"en","trans":[{"dst":"Life is short, I use Python","
prefixWrap":0,"src":"\\u4eba\\u751f\\u82e6\\u77ed\\uff0c\\u6211\\u7528python","relation
":[],"result":[[0,"Life is short, I use Python",["0|27"],[],["0|27"],["0|27"]]]}
],"dict":[],"keywords":[{"means":["life is but a span"],"word":"\\u4eba\\u751f\\u82
e6\\u77ed"},{"means":["\\u5de8\\u86c7\\uff0c\\u5927\\u87d2"],"word":"python"}]}


转义字符报错问题:
https://blog.csdn.net/u011242657/article/details/64437612


# 如果我们还想批量翻译?
# 相当于在终端里面实现了一个翻译工具

# 如果我们还想不用手动输出中文英文?
# 发一次语言检测......作业

"""

# 2 使用代理

# 问题:为什么爬虫需要使用代理?
"""问题:为什么爬虫需要使用代理?

因为 爬虫每秒钟访问很多次 ?

淘宝 京东 为什么访问很多次?ip不同,服务器不把我们当为爬虫

1. 让服务器以为不是同一个客户端在请求:保证单位时间爬取更多又不会被判定为爬虫

2. 防止我们的真实地址被泄露,防止被追究:爬虫是灰色产业

如果我们不用代理,爬到数据进行数据分析,别人会跟踪到你的ip
新浪查到哪个大厦很多人访问它的ip,知道爬虫班又开始了

不开GPS也可以定位自己地址,因为ip的关系(不是全部原因)

高匿IP能够更好的隐瞒

# 米扑代理: https://proxy.mimvp.com/ ok

https://proxy.coderbusy.com/ 码农很忙(2018.12.3访问不了)

"""

# 代理举例
"""

# 代理帮助我们发送请求,接收响应
# 代理包含虚拟一个IP地址(寄信人),服务器就是收信人

# nginx:反向代理,我们不知道最终的服务器的细节;安全一些,别人攻击不到服务器
# :正向代理,我们非常知道最终服务器比如说是google

# 添加proxy,就是个字典


# 用米扑代理: https://proxy.mimvp.com/ ok
import requests
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"}
proxies = {
    'http':'117.191.11.106'
}
r = requests.get('http://www.baidu.com', proxies = proxies, headers = headers)
print(r.status_code)

# 使用代理ip
# 检查ip的可用性

# 后续还得自己深入学习..........


### 使用代理ip 注意:
# - 准备一堆的ip地址,组成ip池,随机选择一个ip来时用
#
# - 如何随机选择代理ip,让使用次数较少的ip地址有更大的可能性被用到
#   - {"ip":ip,"times":0}
#   - [{},{},{},{},{}],对这个ip的列表进行排序,按照使用次数进行排序
#   - 选择使用次数较少的10个ip,从中随机选择一个
#
# - 检查ip的可用性
#   - 可以使用requests添加超时参数,判断ip地址的质量
#   - 在线代理ip质量检测的网站


"""

# 3. 处理 cookies session

#1.  cookie和session区别:
"""
cookie和session区别:

cookie数据存放在客户的浏览器上,session数据放在服务器上。
cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

"""

#2.  爬虫处理cookie和session
"""
爬虫处理cookie和session

带上cookie、session的好处:
	能够请求到登录之后的页面

带上cookie、session的弊端:
	一套cookie和session往往和一个用户对应
	请求太快,请求次数太多,容易被服务器识别为爬虫

不需要cookie的时候尽量不去使用cookie
    
但是为了获取登录之后的页面,我们必须发送带有cookies的请求

"""

#3. 携带cookie请求
"""
### 携带cookie请求
- 携带一堆cookie进行请求,把cookie组成cookie池
"""

### 使用requests提供的session类来请求登陆之后的网站的思路
"""
### 使用requests提供的session类来请求登陆之后的网站的思路
- 实例化session
- 先使用session发送请求,登录对网站,把cookie保存在session中
- 再使用session请求登陆之后才能访问的网站,session能够自动的携带登录成功时保存在其中的cookie,进行请求
"""
### 不发送post请求,使用cookie获取登录后的页面
"""
### 不发送post请求,使用cookie获取登录后的页面
- cookie过期时间很长的网站
- 在cookie过期之前能够拿到所有的数据,比较麻烦
- 配合其他程序一起使用,其他程序专门获取cookie,当前程序专门请求页面

"""

#4. 获取登录后的页面的三种方式
"""
### 获取登录后的页面的三种方式
- 实例化session,使用session发送post请求,在使用他获取登陆后的页面
- headers中添加cookie键,值为cookie字符串
- 在请求方法中添加cookies参数,接收字典形式的cookie。字典形式的cookie中的键是cookie的name对应的值,值是cookie的value对应的值

"""

#5. 应用:使用session登录人人网
"""应用:使用session登录人人网

整个就在讨论,如果用session,用cookies会怎么样?还没实验完

import requests

session = requests.session()
post_url = "https://mail.163.com"
post_data = {"email":"[email protected]", "password":"252324"}
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
}
#使用session发送post请求,cookie保存在其中
session.post(post_url,data=post_data,headers=headers)

#在使用session进行请求登陆之后才能访问的地址
r = session.get("https://mail.163.com/js6/main.jsp?sid=mBqaFyITkEFIcBaESITTzkFuAjkGqPbk&df=mail163_letter",headers=headers)

#保存页面
with open("1631.html","w",encoding="utf-8") as f:
    f.write(r.content.decode())

3.3 正则表达式

to be continued

3.4 抓取猫眼电影的排行

to be continued

你可能感兴趣的:(爬虫=框架=)