zoukankan      html  css  js  c++  java
  • 概述和HTTP请求 和 响应处理

    1、概述

      爬虫,应该称为网络爬虫,也叫网页蜘蛛人,网络蚂蚁等

      搜索引擎,就是网络爬虫的应用者

    2、爬虫分类

      通用爬虫:

        常见就是搜索引擎,无差别的收集数据,存储,提交关键字,构建索引库,给用户提供搜索接口

        爬取一般流程:

          1、初始一批URL,将这些URL放到待爬的队列

          2、从队列取出这些URL,通过DNS 解析IP ,对IP 对应的站点下载HTML页面,保存到本地服务器中,爬取完URL放到已经爬取的队列中

          3、分析这些网页内筒,找出网页里面的其他关心的URL连接,继续执行第二步,直到爬取条件结束。

        搜索引擎如何获取一个新网站的URL

        • 新网站主动提交给搜索引擎
        • 通过其他网站页面的外连接
        • 搜索引擎和DNS 服务商合作,获取最新收录的网站。

      聚焦爬虫:

        有针对的编写特定领域数据的爬虫程序,针对某些 类别的数据采集的爬虫,是面向主体的爬虫

    3、Robots 协议:

      指定一个robots.txt 文件,告诉爬虫引擎什么可以爬,什么不可以爬

      /  表示网站根目录, 表示网站的所有目录

      Allow:允许, Disallow:不允许

      可以使用通配符

      例如:淘宝:http://www.taobao.com/robots.txt    

    View Code

      这是一个君子协定,爬亦有道

      这个协议为了让搜索引擎更有效率的搜索自己内容,提供了如Sitemap 这样的文件

      Sitemap 往往死一个XML 文件,提供了网站想让大家爬取的内容的更新信息

      这个文件禁止爬取的往往又是我们可能感兴趣的内容,它反而泄露了这些地址。

    4、HTTP请求和响应的处理

      其实爬取网页就是通过HTTP 协议访问网页, 不过通过浏览器访问往往是认为行为,把这种行为变成程序来访问。

      urllib包:

        urllib 是标准库,它一个工具包模块,包含下面的模块处理 url

        • urllib.request 用于打开和读写url
        • urllib.error 包含了有urllib.request引起的异常。
        • urllib.parse 用于解析url
        • urllib.robotparser 分析robots.txt 文件

        Python2 中提供了urlib 和urllib2 ,前者 提供了较为底层的接口,urllib2 对urllib 进行了进一步的封装,P樱桃红3中将urllib合并到饿了urllib中,并更名为标准库urllib包

      urllib.request模块

        模块定义了在基本和摘要式身份验证,重定向,cookies等应用中打开url(主要是HTTP)的函数和类

        urlopen方法:

          urlopen(url,data=None)

          url 是链接地址字符串,或请求类的实例

          data提交的数据,如果data为None,发起的是GET请求,否则发起POST请求,

          见 urllib.request.Requset.get_method返回 http.client.HTTPResponse类的响应对象,这是一个类文件对象    

     1 from urllib.request import urlopen
     2 from urllib import request
     3 
     4 
     5 # 打开一个url返回一个响应对象,类文件对象
     6 # 下面的链接,会301 跳转
     7 response = urlopen('https://www.bing.com') #GET 方法
     8 print(response)-----类文件对象
     9 with response:
    10     print(1, type(response))
    11     print(2, response.status, response.reason)
    12     print(3, response.geturl)
    13     print(4, response.info())
    14     print(5, response.read())
    15 
    16 print(response.closed)
    打印结果

        上面,通过urllib.requset.urlopen 方法,发起一个HTTP的GET请求,web 服务器返回了网页内容,响应的数据被封装到类文件对象中,可以通过read方法,readline方法,readlines方法,获取数据,status,和reason   表示状态码, info方法表示返回header信息等

      User-Agent问题

        上例的代码非常精简,即可以获得网站的响应数据,但是目前urlopen方法通过url 字符串和data发起HTTP请求

        如果想修改HTTP头,例如:useragent 就得借助其他方式

        原码中构造的useragent 如下:    

     1 class OpenerDirector:
     2     def __init__(self):
     3         client_version = "Python-urllib/%s" % __version__
     4         self.addheaders = [('User-agent', client_version)]
     5         # self.handlers is retained only for backward compatibility
     6         self.handlers = []
     7         # manage the individual handlers
     8         self.handle_open = {}
     9         self.handle_error = {}
    10         self.process_response = {}
    11         self.process_request = {}

        当前显示为 Python-urllib/3.7

        有些网站是反爬虫的,所以要把爬虫伪装成浏览器,随便打开一个浏览器,复制浏览器的UA(useragent) 值,用来伪装。

      Request类

        Request(url, data=None, headers={} )

        初始化方法,构造一个请求对象,可添加一个header的字典

        data 参数决定是GET 还是POST 请求(data 为None是GET,有数据,就是POST)

        add_header(key, val) 为header总增加一个键值对。    

     1 from urllib.request import Request, urlopen
     2 
     3 # 打开一个url 返回一个Requset 请求对象
     4 # url = 'http://movie.douban.com/' 注意尾部的斜杆一定要有
     5 url = 'http://www.bing.com/'
     6 
     7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     8 
     9 # 构造一个请求对象
    10 request = Request(url)
    11 request.add_header('User-Agent',ua)
    12 
    13 print(type(request),'=============')
    14 print(5,request.get_header('User-Agent'))
    15 # 构建响应对象
    16 response = urlopen(request, timeout=20) # requset对象或者url 都可以
    17 
    18 print(type(response))
    19 
    20 
    21 with response:
    22     # getcode本质上返回的就是 status
    23     print(1, response.status, response.getcode(),response.reason)
    24     # 返回数据的url,如果重定向,这个url和原始url不一样
    25     print(2, response.geturl())
    26     # 返回响应头信息
    27     print(3, response.info())
    28     # 读取返回的内容
    29     print(4, response.read())
    30 
    31 print(5,request.get_header('User-Agent'))
    32 print(6,'user-agent'.capitalize())
    打印结果

       urllib.parse 模块

       该模块可以完成对url的编解码

         编码:urlencode函数第一个参数要求是一个字典或者二元组序列

    1 from urllib import parse
    2 
    3 u = parse.urlencode({
    4     'url':'http://www.magedu.com/python',
    5     'p_url':'http:www.magedu.com/python?id=1&name=张三'
    6 })
    7 print(u)
    url=http%3A%2F%2Fwww.magedu.com%2Fpython&p_url=http%3Awww.magedu.com%2Fpython%3Fid%3D1%26name%3D%E5%BC%A0%E4%B8%89

       从运行结果来看冒号。斜杆 & 等号,问号都被编码,%之后实际上是单字节十六进制表示的值

      一般来说,url中的地址部分,一般不需要使用中文路径,但是参数部分,不管 GET 还是post 方法,提交的数据中,可能有斜杆等符号,这样的字符表示数据,不表示元字符,如果直接发送给服务器端,就会导致接收方无法判断谁是元字符,谁是数据,为了安全,一般会将数据部分的字符串做url 编码,这样就不会有歧义了

    ,后来可以传送中文,同样会做编码,一般先按照字符集的encoding要求转化成字节序列,每一个字节对应的十六进制字符串前加上百分号即可。

     1 '''
     2 网页使用utf-8 编码
     3 https://www.baidu.com/s?wd=中
     4 上面的url编码后,如下:
     5 https://www.baidu.com/s?wd=%E4%B8%AD
     6 '''
     7 from urllib import parse
     8 
     9 u = parse.urlencode({'wd':'中'}) # 编码
    10 print(u)
    11 
    12 url = 'https://www.baidu.com/s?{}'.format(u)
    13 print(url)
    14 
    15 print('中'.encode('utf-8'))
    16 # 解码
    17 print(parse.unquote(u))
    18 print(parse.unquote(url))

       打印结果:

    1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt21.py
    2 wd=%E4%B8%AD
    3 https://www.baidu.com/s?wd=%E4%B8%AD
    4 b'xe4xb8xad'
    5 wd=中
    6 https://www.baidu.com/s?wd=中
    7 
    8 Process finished with exit code 0

    5、提交方法method

      最常用的HTTP交互 数据的方法是GET ,POST

      GET 方法,数据是通过URL 传递的,也就是说数据时候在http 报文的header部分

      POST方法,数据是放在http报文的body 部分提交的

      数据都是键值对形式,多个参数之间使用&符号链接,

       GET方法:

      连接 bing 搜索引擎官网,获取一个搜索的URL: http://cn.bing.com/search?q=张三

      需求:

      请写程序需完成对关键字的bing 搜索, 将返回的结果保存到一个网页文件中。  

     1 from urllib.request import Request, urlopen
     2 from urllib.parse import urlencode
     3 
     4 keyword = input('>>输入关键字')
     5 
     6 data = urlencode({'q':keyword})
     7 
     8 base_url = 'http://cn.bing.com/search'
     9 
    10 url = '{}?{}'.format(base_url, data)
    11 
    12 print(url)
    13 
    14 # 伪装
    15 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    16 request = Request(url, headers={'User-agent':ua})
    17 response = urlopen(request)
    18 
    19 with response:
    20     with open('./bing.html', 'wb') as f:
    21         f.write(response.read())

       结果:

       http GET 获取的文本 是字节形式(二进制)

       POST 方法:

         http://httpbin.org/ 测试网站  像一个echo,你发什么,给你什么

     1 from urllib.request import Request, urlopen
     2 from urllib.parse import urlencode
     3 import simplejson
     4 
     5 request = Request('http://httpbin.org/post')
     6 
     7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     8 
     9 request.add_header('User-agent', ua)
    10 
    11 data = urlencode({'name':'张三,@=/&=', 'age':'12'})
    12 
    13 print(data)
    14 
    15 res = urlopen(request, data=data.encode())# POST f方法 Form提交数据
    16 with res:
    17     print(res.read().decode())

       结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt23.py
     2 name=%E5%BC%A0%E4%B8%89%2C%40%3D%2F%26%3D&age=12
     3 {
     4   "args": {}, 
     5   "data": "", 
     6   "files": {}, 
     7   "form": {
     8     "age": "12", 
     9     "name": "u5f20u4e09,@=/&="
    10   }, 
    11   "headers": {
    12     "Accept-Encoding": "identity", 
    13     "Connection": "close", 
    14     "Content-Length": "48", 
    15     "Content-Type": "application/x-www-form-urlencoded", 
    16     "Host": "httpbin.org", 
    17     "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36"
    18   }, 
    19   "json": null, 
    20   "origin": "61.149.196.193", 
    21   "url": "http://httpbin.org/post"
    22 }
    23 
    24 
    25 Process finished with exit code 0

         

      处理JSON数据 

         查看豆瓣电影,看到最近热门电影的热门

        

         通过分析,我们知道这部分内容,是通过AJAX 从后台拿到的json数据

          

        访问ur 是:https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0

          

           服务器返回的数据如上

          

    1 from urllib import parse
    2 将url解码:
    3 print(parse.unquote('https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0'))
    4 
    5 ----------------------------------------------------------------------------------
    6 https://movie.douban.com/j/search_subjects?type=movie&tag=热门&page_limit=50&page_start=0

         通过代码获取上述截图内容:

      

     6、HTTPS 证书忽略

      HTTPS使用SSL 安全套接层协议,在传输层对网路数据进行加密,HTTPS 使用的时候,需要证书,而证书需要cA认证 

     1 from urllib.request import Request, urlopen
     2 
     3 # 可以访问
     4 # request = Request('http://www.12306.cn/mormhweb')
     5 # request = Request('https://www.baidu.com')
     6 
     7 request = Request('https://www.12306.cn/mormhweb/')
     8 
     9 
    10 print(request)
    11 
    12 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    13 
    14 request.add_header('User-agent', ua)
    15 
    16 with urlopen(request) as res:
    17     print(res._method)
    18     print(res.read())

        

      

      忽略证书不安全信息:  

     1 from urllib.request import Request, urlopen
     2 import ssl
     3 
     4 # 可以访问
     5 # request = Request('http://www.12306.cn/mormhweb')
     6 # request = Request('https://www.baidu.com')
     7 
     8 request = Request('https://www.12306.cn/mormhweb/')
     9 
    10 
    11 print(request)
    12 
    13 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    14 
    15 request.add_header('User-agent', ua)
    16 # 忽略不信任的证书(不用校验的上下文)
    17 context = ssl._create_unverified_context()
    18 res = urlopen(request, context=context)
    19 
    20 
    21 with res:
    22     print(res._method)
    23     print(res.geturl())
    24     print(res.read().decode())

      

    7、urllib3 库

      https:// urllib3.readthedocs.io/en/latest

      标准库urllib缺少了一些关键的功能,非标准库的第三方库 urlib3 提供了,比如说连接池管理

      安装:pip install urllib3  

     1 import urllib3
     2 
     3 url = 'http://movie.douban.com/'
     4 
     5 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     6 
     7 # 连接池管理
     8 with urllib3.PoolManager() as http:
     9     response = http.request('GET', url, headers={"User-agent":ua})
    10     print(1,type(response))
    11     print(2,response.status, response.reason)
    12     print(3,response.headers)
    13     print(4,response.data.decode())

       结果:

    View Code

    8、requests库(开发真正用的库)

      requests 使用了 urllib3, 但是 API 更加友好,推荐使用

     1 import requests
     2 
     3 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     4 
     5 url = 'http://movie.douban.com/'
     6 
     7 response = requests.request('GET', url,headers={'User-agent':ua})
     8 
     9 with response:
    10     print(type(response))
    11     print(response)
    12     print(response.url)
    13     print((response.status_code))
    14     print(response.request.headers) #请求头
    15     print(response.headers) # 响应头
    16     print(response.encoding)
    17     response.encoding = 'utf-8'
    18     print(response.text[:100])
    19 
    20     with open('./movie.html', 'w', encoding='utf-8') as f:
    21         f.write(response.text) # 保存文件

      结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt25.py
     2 <class 'requests.models.Response'>
     3 <Response [200]>
     4 https://movie.douban.com/
     5 200
     6 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
     7 {'Date': 'Wed, 05 Dec 2018 03:34:12 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=30', 'Vary': 'Accept-Encoding', 'X-Xss-Protection': '1; mode=block', 'X-Douban-Mobileapp': '0', 'Expires': 'Sun, 1 Jan 2006 01:00:00 GMT', 'Pragma': 'no-cache', 'Cache-Control': 'must-revalidate, no-cache, private', 'Set-Cookie': 'll="108288"; path=/; domain=.douban.com; expires=Thu, 05-Dec-2019 03:34:12 GMT, bid=8QfNwA452hU; Expires=Thu, 05-Dec-19 03:34:12 GMT; Domain=.douban.com; Path=/', 'X-DOUBAN-NEWBID': '8QfNwA452hU', 'X-DAE-Node': 'brand15', 'X-DAE-App': 'movie', 'Server': 'dae', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip'}
     8 utf-8
     9 <!DOCTYPE html>
    10 <html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
    11 <head>
    12     <meta http-equiv="
    13 
    14 Process finished with exit code 0

      request默认使用Session 对象,是为了在多次 和服务器交互中保留 会话的信息,例如cookie

      否则,每次都要重新发起请求

      

     1 # 直接使用Session
     2 import requests
     3 
     4 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     5 
     6 urls = ['https://www.baidu.com','https://www.baidu.com']
     7 
     8 session = requests.Session()
     9 with session:
    10     for url in urls:
    11         # response = session.get(url, headers={'User-agent':ua})
    12         response = requests.request('GET', url, headers={'User-agent':ua}) # 相当于每次都是新的请求,也就是开启了两个浏览器而已
    13         print(response)
    14         with response:
    15             print(response.request.headers)
    16             print(response.cookies)
    17             print(response.text[:20])
    18             print('----------------------------------------------')
    19 '''
    20 D:python3.7python.exe E:/code_pycharm/test_in_class/tt19.py
    21 <Response [200]>
    22 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    23 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC144A1F6BEA823FF4F5:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC144A1F6BEA823FF4F5 for .baidu.com/>, <Cookie H_PS_PSSID=1444_21081_27509 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    24 <!DOCTYPE html>
    25 <!--
    26 ----------------------------------------------
    27 <Response [200]>
    28 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    29 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC14FA9EECCB0280B074:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC14FA9EECCB0280B074 for .baidu.com/>, <Cookie H_PS_PSSID=26523_1469_25810_21098_26350_22073 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    30 <!DOCTYPE html>
    31 <!--
    32 ----------------------------------------------
    33 
    34 Process finished with exit code 0
    35 
    36 '''
    37 
    38 with session:
    39     for url in urls:
    40         response = session.get(url, headers={'User-agent':ua})
    41         # response = requests.request('GET', url, headers={'User-agent':ua})
    42         print(response)
    43         with response:
    44             print(response.request.headers)
    45             print(response.cookies)
    46             print(response.text[:20])
    47             print('----------------------------------------------')
    48 '''
    49 D:python3.7python.exe E:/code_pycharm/test_in_class/tt19.py
    50 <Response [200]>
    51 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    52 <RequestsCookieJar[<Cookie BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1 for .baidu.com/>, <Cookie BIDUPSID=5A320955507582B839E723DB6F55B2BD for .baidu.com/>, <Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie PSTM=1543981366 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    53 <!DOCTYPE html>
    54 <!--
    55 ----------------------------------------------
    56 <Response [200]>  第二次访问,带上了cookie
    57 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1; BIDUPSID=5A320955507582B839E723DB6F55B2BD; H_PS_PSSID=1434_21091_18559_27245_27509; PSTM=1543981366; delPer=0; BDSVRTM=0; BD_HOME=0'}
    58 <RequestsCookieJar[<Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    59 <!DOCTYPE html>
    60 <!--
    61 ----------------------------------------------
    62 
    63 Process finished with exit code 0
    64 
    65 '''

    1、概述

      爬虫,应该称为网络爬虫,也叫网页蜘蛛人,网络蚂蚁等

      搜索引擎,就是网络爬虫的应用者

    2、爬虫分类

      通用爬虫:

        常见就是搜索引擎,无差别的收集数据,存储,提交关键字,构建索引库,给用户提供搜索接口

        爬取一般流程:

          1、初始一批URL,将这些URL放到待爬的队列

          2、从队列取出这些URL,通过DNS 解析IP ,对IP 对应的站点下载HTML页面,保存到本地服务器中,爬取完URL放到已经爬取的队列中

          3、分析这些网页内筒,找出网页里面的其他关心的URL连接,继续执行第二步,直到爬取条件结束。

        搜索引擎如何获取一个新网站的URL

        • 新网站主动提交给搜索引擎
        • 通过其他网站页面的外连接
        • 搜索引擎和DNS 服务商合作,获取最新收录的网站。

      聚焦爬虫:

        有针对的编写特定领域数据的爬虫程序,针对某些 类别的数据采集的爬虫,是面向主体的爬虫

    3、Robots 协议:

      指定一个robots.txt 文件,告诉爬虫引擎什么可以爬,什么不可以爬

      /  表示网站根目录, 表示网站的所有目录

      Allow:允许, Disallow:不允许

      可以使用通配符

      例如:淘宝:http://www.taobao.com/robots.txt    

    View Code

      这是一个君子协定,爬亦有道

      这个协议为了让搜索引擎更有效率的搜索自己内容,提供了如Sitemap 这样的文件

      Sitemap 往往死一个XML 文件,提供了网站想让大家爬取的内容的更新信息

      这个文件禁止爬取的往往又是我们可能感兴趣的内容,它反而泄露了这些地址。

    4、HTTP请求和响应的处理

      其实爬取网页就是通过HTTP 协议访问网页, 不过通过浏览器访问往往是认为行为,把这种行为变成程序来访问。

      urllib包:

        urllib 是标准库,它一个工具包模块,包含下面的模块处理 url

        • urllib.request 用于打开和读写url
        • urllib.error 包含了有urllib.request引起的异常。
        • urllib.parse 用于解析url
        • urllib.robotparser 分析robots.txt 文件

        Python2 中提供了urlib 和urllib2 ,前者 提供了较为底层的接口,urllib2 对urllib 进行了进一步的封装,P樱桃红3中将urllib合并到饿了urllib中,并更名为标准库urllib包

      urllib.request模块

        模块定义了在基本和摘要式身份验证,重定向,cookies等应用中打开url(主要是HTTP)的函数和类

        urlopen方法:

          urlopen(url,data=None)

          url 是链接地址字符串,或请求类的实例

          data提交的数据,如果data为None,发起的是GET请求,否则发起POST请求,

          见 urllib.request.Requset.get_method返回 http.client.HTTPResponse类的响应对象,这是一个类文件对象    

     1 from urllib.request import urlopen
     2 from urllib import request
     3 
     4 
     5 # 打开一个url返回一个响应对象,类文件对象
     6 # 下面的链接,会301 跳转
     7 response = urlopen('https://www.bing.com') #GET 方法
     8 print(response)-----类文件对象
     9 with response:
    10     print(1, type(response))
    11     print(2, response.status, response.reason)
    12     print(3, response.geturl)
    13     print(4, response.info())
    14     print(5, response.read())
    15 
    16 print(response.closed)
    打印结果

        上面,通过urllib.requset.urlopen 方法,发起一个HTTP的GET请求,web 服务器返回了网页内容,响应的数据被封装到类文件对象中,可以通过read方法,readline方法,readlines方法,获取数据,status,和reason   表示状态码, info方法表示返回header信息等

      User-Agent问题

        上例的代码非常精简,即可以获得网站的响应数据,但是目前urlopen方法通过url 字符串和data发起HTTP请求

        如果想修改HTTP头,例如:useragent 就得借助其他方式

        原码中构造的useragent 如下:    

     1 class OpenerDirector:
     2     def __init__(self):
     3         client_version = "Python-urllib/%s" % __version__
     4         self.addheaders = [('User-agent', client_version)]
     5         # self.handlers is retained only for backward compatibility
     6         self.handlers = []
     7         # manage the individual handlers
     8         self.handle_open = {}
     9         self.handle_error = {}
    10         self.process_response = {}
    11         self.process_request = {}

        当前显示为 Python-urllib/3.7

        有些网站是反爬虫的,所以要把爬虫伪装成浏览器,随便打开一个浏览器,复制浏览器的UA(useragent) 值,用来伪装。

      Request类

        Request(url, data=None, headers={} )

        初始化方法,构造一个请求对象,可添加一个header的字典

        data 参数决定是GET 还是POST 请求(data 为None是GET,有数据,就是POST)

        add_header(key, val) 为header总增加一个键值对。    

     1 from urllib.request import Request, urlopen
     2 
     3 # 打开一个url 返回一个Requset 请求对象
     4 # url = 'http://movie.douban.com/' 注意尾部的斜杆一定要有
     5 url = 'http://www.bing.com/'
     6 
     7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     8 
     9 # 构造一个请求对象
    10 request = Request(url)
    11 request.add_header('User-Agent',ua)
    12 
    13 print(type(request),'=============')
    14 print(5,request.get_header('User-Agent'))
    15 # 构建响应对象
    16 response = urlopen(request, timeout=20) # requset对象或者url 都可以
    17 
    18 print(type(response))
    19 
    20 
    21 with response:
    22     # getcode本质上返回的就是 status
    23     print(1, response.status, response.getcode(),response.reason)
    24     # 返回数据的url,如果重定向,这个url和原始url不一样
    25     print(2, response.geturl())
    26     # 返回响应头信息
    27     print(3, response.info())
    28     # 读取返回的内容
    29     print(4, response.read())
    30 
    31 print(5,request.get_header('User-Agent'))
    32 print(6,'user-agent'.capitalize())
    打印结果

       urllib.parse 模块

       该模块可以完成对url的编解码

         编码:urlencode函数第一个参数要求是一个字典或者二元组序列

    1 from urllib import parse
    2 
    3 u = parse.urlencode({
    4     'url':'http://www.magedu.com/python',
    5     'p_url':'http:www.magedu.com/python?id=1&name=张三'
    6 })
    7 print(u)
    url=http%3A%2F%2Fwww.magedu.com%2Fpython&p_url=http%3Awww.magedu.com%2Fpython%3Fid%3D1%26name%3D%E5%BC%A0%E4%B8%89

       从运行结果来看冒号。斜杆 & 等号,问号都被编码,%之后实际上是单字节十六进制表示的值

      一般来说,url中的地址部分,一般不需要使用中文路径,但是参数部分,不管 GET 还是post 方法,提交的数据中,可能有斜杆等符号,这样的字符表示数据,不表示元字符,如果直接发送给服务器端,就会导致接收方无法判断谁是元字符,谁是数据,为了安全,一般会将数据部分的字符串做url 编码,这样就不会有歧义了

    ,后来可以传送中文,同样会做编码,一般先按照字符集的encoding要求转化成字节序列,每一个字节对应的十六进制字符串前加上百分号即可。

     1 '''
     2 网页使用utf-8 编码
     3 https://www.baidu.com/s?wd=中
     4 上面的url编码后,如下:
     5 https://www.baidu.com/s?wd=%E4%B8%AD
     6 '''
     7 from urllib import parse
     8 
     9 u = parse.urlencode({'wd':'中'}) # 编码
    10 print(u)
    11 
    12 url = 'https://www.baidu.com/s?{}'.format(u)
    13 print(url)
    14 
    15 print('中'.encode('utf-8'))
    16 # 解码
    17 print(parse.unquote(u))
    18 print(parse.unquote(url))

       打印结果:

    1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt21.py
    2 wd=%E4%B8%AD
    3 https://www.baidu.com/s?wd=%E4%B8%AD
    4 b'xe4xb8xad'
    5 wd=中
    6 https://www.baidu.com/s?wd=中
    7 
    8 Process finished with exit code 0

    5、提交方法method

      最常用的HTTP交互 数据的方法是GET ,POST

      GET 方法,数据是通过URL 传递的,也就是说数据时候在http 报文的header部分

      POST方法,数据是放在http报文的body 部分提交的

      数据都是键值对形式,多个参数之间使用&符号链接,

       GET方法:

      连接 bing 搜索引擎官网,获取一个搜索的URL: http://cn.bing.com/search?q=张三

      需求:

      请写程序需完成对关键字的bing 搜索, 将返回的结果保存到一个网页文件中。  

     1 from urllib.request import Request, urlopen
     2 from urllib.parse import urlencode
     3 
     4 keyword = input('>>输入关键字')
     5 
     6 data = urlencode({'q':keyword})
     7 
     8 base_url = 'http://cn.bing.com/search'
     9 
    10 url = '{}?{}'.format(base_url, data)
    11 
    12 print(url)
    13 
    14 # 伪装
    15 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    16 request = Request(url, headers={'User-agent':ua})
    17 response = urlopen(request)
    18 
    19 with response:
    20     with open('./bing.html', 'wb') as f:
    21         f.write(response.read())

       结果:

       http GET 获取的文本 是字节形式(二进制)

       POST 方法:

         http://httpbin.org/ 测试网站  像一个echo,你发什么,给你什么

     1 from urllib.request import Request, urlopen
     2 from urllib.parse import urlencode
     3 import simplejson
     4 
     5 request = Request('http://httpbin.org/post')
     6 
     7 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     8 
     9 request.add_header('User-agent', ua)
    10 
    11 data = urlencode({'name':'张三,@=/&=', 'age':'12'})
    12 
    13 print(data)
    14 
    15 res = urlopen(request, data=data.encode())# POST f方法 Form提交数据
    16 with res:
    17     print(res.read().decode())

       结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt23.py
     2 name=%E5%BC%A0%E4%B8%89%2C%40%3D%2F%26%3D&age=12
     3 {
     4   "args": {}, 
     5   "data": "", 
     6   "files": {}, 
     7   "form": {
     8     "age": "12", 
     9     "name": "u5f20u4e09,@=/&="
    10   }, 
    11   "headers": {
    12     "Accept-Encoding": "identity", 
    13     "Connection": "close", 
    14     "Content-Length": "48", 
    15     "Content-Type": "application/x-www-form-urlencoded", 
    16     "Host": "httpbin.org", 
    17     "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36"
    18   }, 
    19   "json": null, 
    20   "origin": "61.149.196.193", 
    21   "url": "http://httpbin.org/post"
    22 }
    23 
    24 
    25 Process finished with exit code 0

         

      处理JSON数据 

         查看豆瓣电影,看到最近热门电影的热门

        

         通过分析,我们知道这部分内容,是通过AJAX 从后台拿到的json数据

          

        访问ur 是:https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0

          

           服务器返回的数据如上

          

    1 from urllib import parse
    2 将url解码:
    3 print(parse.unquote('https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0'))
    4 
    5 ----------------------------------------------------------------------------------
    6 https://movie.douban.com/j/search_subjects?type=movie&tag=热门&page_limit=50&page_start=0

         通过代码获取上述截图内容:

      

     6、HTTPS 证书忽略

      HTTPS使用SSL 安全套接层协议,在传输层对网路数据进行加密,HTTPS 使用的时候,需要证书,而证书需要cA认证 

     1 from urllib.request import Request, urlopen
     2 
     3 # 可以访问
     4 # request = Request('http://www.12306.cn/mormhweb')
     5 # request = Request('https://www.baidu.com')
     6 
     7 request = Request('https://www.12306.cn/mormhweb/')
     8 
     9 
    10 print(request)
    11 
    12 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    13 
    14 request.add_header('User-agent', ua)
    15 
    16 with urlopen(request) as res:
    17     print(res._method)
    18     print(res.read())

        

      

      忽略证书不安全信息:  

     1 from urllib.request import Request, urlopen
     2 import ssl
     3 
     4 # 可以访问
     5 # request = Request('http://www.12306.cn/mormhweb')
     6 # request = Request('https://www.baidu.com')
     7 
     8 request = Request('https://www.12306.cn/mormhweb/')
     9 
    10 
    11 print(request)
    12 
    13 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
    14 
    15 request.add_header('User-agent', ua)
    16 # 忽略不信任的证书(不用校验的上下文)
    17 context = ssl._create_unverified_context()
    18 res = urlopen(request, context=context)
    19 
    20 
    21 with res:
    22     print(res._method)
    23     print(res.geturl())
    24     print(res.read().decode())

      

    7、urllib3 库

      https:// urllib3.readthedocs.io/en/latest

      标准库urllib缺少了一些关键的功能,非标准库的第三方库 urlib3 提供了,比如说连接池管理

      安装:pip install urllib3  

     1 import urllib3
     2 
     3 url = 'http://movie.douban.com/'
     4 
     5 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     6 
     7 # 连接池管理
     8 with urllib3.PoolManager() as http:
     9     response = http.request('GET', url, headers={"User-agent":ua})
    10     print(1,type(response))
    11     print(2,response.status, response.reason)
    12     print(3,response.headers)
    13     print(4,response.data.decode())

       结果:

    View Code

    8、requests库(开发真正用的库)

      requests 使用了 urllib3, 但是 API 更加友好,推荐使用

     1 import requests
     2 
     3 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     4 
     5 url = 'http://movie.douban.com/'
     6 
     7 response = requests.request('GET', url,headers={'User-agent':ua})
     8 
     9 with response:
    10     print(type(response))
    11     print(response)
    12     print(response.url)
    13     print((response.status_code))
    14     print(response.request.headers) #请求头
    15     print(response.headers) # 响应头
    16     print(response.encoding)
    17     response.encoding = 'utf-8'
    18     print(response.text[:100])
    19 
    20     with open('./movie.html', 'w', encoding='utf-8') as f:
    21         f.write(response.text) # 保存文件

      结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt25.py
     2 <class 'requests.models.Response'>
     3 <Response [200]>
     4 https://movie.douban.com/
     5 200
     6 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
     7 {'Date': 'Wed, 05 Dec 2018 03:34:12 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=30', 'Vary': 'Accept-Encoding', 'X-Xss-Protection': '1; mode=block', 'X-Douban-Mobileapp': '0', 'Expires': 'Sun, 1 Jan 2006 01:00:00 GMT', 'Pragma': 'no-cache', 'Cache-Control': 'must-revalidate, no-cache, private', 'Set-Cookie': 'll="108288"; path=/; domain=.douban.com; expires=Thu, 05-Dec-2019 03:34:12 GMT, bid=8QfNwA452hU; Expires=Thu, 05-Dec-19 03:34:12 GMT; Domain=.douban.com; Path=/', 'X-DOUBAN-NEWBID': '8QfNwA452hU', 'X-DAE-Node': 'brand15', 'X-DAE-App': 'movie', 'Server': 'dae', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip'}
     8 utf-8
     9 <!DOCTYPE html>
    10 <html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
    11 <head>
    12     <meta http-equiv="
    13 
    14 Process finished with exit code 0

      request默认使用Session 对象,是为了在多次 和服务器交互中保留 会话的信息,例如cookie

      否则,每次都要重新发起请求

      

     1 # 直接使用Session
     2 import requests
     3 
     4 ua = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36'
     5 
     6 urls = ['https://www.baidu.com','https://www.baidu.com']
     7 
     8 session = requests.Session()
     9 with session:
    10     for url in urls:
    11         # response = session.get(url, headers={'User-agent':ua})
    12         response = requests.request('GET', url, headers={'User-agent':ua}) # 相当于每次都是新的请求,也就是开启了两个浏览器而已
    13         print(response)
    14         with response:
    15             print(response.request.headers)
    16             print(response.cookies)
    17             print(response.text[:20])
    18             print('----------------------------------------------')
    19 '''
    20 D:python3.7python.exe E:/code_pycharm/test_in_class/tt19.py
    21 <Response [200]>
    22 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    23 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC144A1F6BEA823FF4F5:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC144A1F6BEA823FF4F5 for .baidu.com/>, <Cookie H_PS_PSSID=1444_21081_27509 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    24 <!DOCTYPE html>
    25 <!--
    26 ----------------------------------------------
    27 <Response [200]>
    28 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    29 <RequestsCookieJar[<Cookie BAIDUID=808F0938C6A9CC14FA9EECCB0280B074:FG=1 for .baidu.com/>, <Cookie BIDUPSID=808F0938C6A9CC14FA9EECCB0280B074 for .baidu.com/>, <Cookie H_PS_PSSID=26523_1469_25810_21098_26350_22073 for .baidu.com/>, <Cookie PSTM=1543981317 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    30 <!DOCTYPE html>
    31 <!--
    32 ----------------------------------------------
    33 
    34 Process finished with exit code 0
    35 
    36 '''
    37 
    38 with session:
    39     for url in urls:
    40         response = session.get(url, headers={'User-agent':ua})
    41         # response = requests.request('GET', url, headers={'User-agent':ua})
    42         print(response)
    43         with response:
    44             print(response.request.headers)
    45             print(response.cookies)
    46             print(response.text[:20])
    47             print('----------------------------------------------')
    48 '''
    49 D:python3.7python.exe E:/code_pycharm/test_in_class/tt19.py
    50 <Response [200]>
    51 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
    52 <RequestsCookieJar[<Cookie BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1 for .baidu.com/>, <Cookie BIDUPSID=5A320955507582B839E723DB6F55B2BD for .baidu.com/>, <Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie PSTM=1543981366 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    53 <!DOCTYPE html>
    54 <!--
    55 ----------------------------------------------
    56 <Response [200]>  第二次访问,带上了cookie
    57 {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3486.0 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'BAIDUID=5A320955507582B839E723DB6F55B2BD:FG=1; BIDUPSID=5A320955507582B839E723DB6F55B2BD; H_PS_PSSID=1434_21091_18559_27245_27509; PSTM=1543981366; delPer=0; BDSVRTM=0; BD_HOME=0'}
    58 <RequestsCookieJar[<Cookie H_PS_PSSID=1434_21091_18559_27245_27509 for .baidu.com/>, <Cookie delPer=0 for .baidu.com/>, <Cookie BDSVRTM=0 for www.baidu.com/>, <Cookie BD_HOME=0 for www.baidu.com/>]>
    59 <!DOCTYPE html>
    60 <!--
    61 ----------------------------------------------
    62 
    63 Process finished with exit code 0
    64 
    65 '''
  • 相关阅读:
    SSRF——和远程文件包含的区别在于远程文件包含多是包含攻击者的主机文件,SSRF是内网主机的文件
    SSRF中的绕过手段——字节总结得比较好,如何绕过SSRF的保护机制,DNS欺骗,使用IPV6地址,十六进制编码、八进制编码、双字编码、URL编码和混合编码等
    SSRF——服务端请求伪造,根因是file_get_contents,fsockopen,curl_exec函数调用,类似远程文件包含,不过是内网机器
    文件包含——本地文件包含和远程文件包含
    文件包含和目录遍历区别——目标都是信息泄露,但手段一个是利用函数来包含web目录以外的文件,另外一个是对web路径访问权限设置不严格导致
    DFS——单词分割,原来还是要使用cached dp才能避免不超时
    模块module间引用和使用本地maven库的jar包
    机器学习西瓜书白话解读笔记---0401-0404、信息和熵的度量
    机器学习实战笔记---0、读大纲
    心得体悟帖---201129(【社会规律】)
  • 原文地址:https://www.cnblogs.com/JerryZao/p/10070093.html
Copyright © 2011-2022 走看看