文章目录

  • Python 3 网络爬虫 笔记 (未完待续)
    • Chap 2 爬虫基础
    • Chap 3 基本库的使用
    • Chap 4 解析库的使用
    • Chap 5 数据存储
    • Chap 6 Ajax 数据爬取
    • Chap 7 动态渲染页面爬取
    • Chap 8 验证码识别
    • Chap 9 代理的使用
    • Chap 10 模拟登录
    • Chap 11 App 的爬取
    • Chap 12 Pyspider 框架
    • Chap 13 Scrapy 框架
    • Chap 14 分布式爬虫
    • Chap 15 分布式爬虫的部署

Python 3 网络爬虫 笔记 (未完待续)



Chap 2 爬虫基础

看书吧就不详述了。



Chap 3 基本库的使用

  • Python 内置的 HTTP 请求库 —— urllib,它包含四个模块:

    1. request 最基本的 HTTP 请求模块,可用于模拟发送请求。只需传入 url 等参数即可。
    2. error 异常处理模块,出现请求错误时,可以捕获异常,进行重试等操作。
    3. parse 工具模块,提供了许多 url 处理方法。
    4. robotparser 用于识别网站的 robots.txt 文件,以判断哪些网站可以爬取,哪些不能。
  • 1. request.urlopen()

    # >>>>>>>>>>>> 通过 request.urlopen() 实现简单的 get 请求
    import urllib.requestresponse = urllib.request.urlopen('https://www.python.org')    # 请求 Python 官网
    print(response.read().decode('utf-8'))    # 打印网页源代码
    print(type(response))    # 这里可见 urlopen 返回的是一个 HTTPResposne 类型的对象
    

    HTTPResposne 类型的对象主要包含 read(), getheader(name), getheaders() 等方法以及 msg, version, status, reason 等属性。

    print(response.status)    # 响应状态码
    print(response.getheaders())    # 响应头信息
    print(response.getheader('Server'))    # 响应头中的 Server 值 —— 服务器用什么搭建的。
    
    urlopen() 的主要参数 说明
    data 传递了此参数,请求方式自动变为 POST
    timeout 用于设置超时时间,单位为秒
    其他 context 参数用来指定 SSL 设置;
    cafile 和 capath 这两个参数分别指定 CA 证书和它的路径
    # >>>>>>>>>>>> data 参数
    import urllib.parse
    import urllib.request# 1. 构造 data 参数: 首先用 urlencode() 方法将参数字典转化为字符串,然后通过 bytes() 方法将该字符串转化为 bytes 类型。
    data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf-8')
    # 2. 传递 bytes 类型的 data 参数, 它是值为 hello 的 word 参数。
    response = urllib.request.urlopen('http://httpbin.org/post', data=data)
    # 3. 可以看到传递的参数出现在了 form 字段中,这就说明模拟了表单提交的方式,以 POST 方式传输数据。
    print(response.read())
    
    # >>>>>>>>>>>> timeout 参数
    import socket
    import urllib.request
    import urllib.errortry:    # 请求测试链接, 设置超时时间为 0.1 秒response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
    except urllib.error.URLError as e:    # 捕获 URLError 异常if isinstance(e.reason, socket.timeout):    # 判断异常是 socket.timeout 类型print('timeout')
    
  • 2. request.Request

    # >>>>>>>>>>>> 通过 Request 对象来构建请求
    import urllib.requestrequest = urllib.request.Request('https://python.org')    # 实例化 Request 对象
    response = urllib.request.urlopen(request)    # urlopen 的参数变成了 Request 对象的实例
    print(response.read().decode('utf-8'))
    
    Request 类的属性 说明
    url 要请求的 url,是必传参数。
    data 必须以 bytes 类型传递,参考 urlopen() 的 data 参数。
    headers 请求头,字典形式,可以通过修改 User-Agent 来伪装浏览器。
    origin_req_host 请求方的 host 名称或 IP。
    method 请求方法,GET,POST等。
    # >>>>>>>>>>>> 传递多个参数构建请求
    from urllib import request, parseurl = 'http://httpbin.org/post'    # 请求的 URL
    para_dict = {'name': 'Gozen Sanji'}    # 参数字典
    headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host': 'httpbin.org'}    # 在 headers 中指定了 UA 和 Host# 1. 将参数字典转化为字符串并转为 bytes 类型
    data = bytes(parse.urlencode(para_dict), encoding='utf-8')
    # 2. 实例化 Request 时传递了4个参数 (传递了 headers 和 data 并指点请求方式为 POST)
    req = request.Request(url=url, data=data, headers=headers, method='POST')
    # 3. 通过 urlopen() 发送请求
    response = request.urlopen(req)
    print(response.read().decode('utf-8'))
    
  • 3. request 高级用法:利用 Handler 构建 Opener

    # >>>>>>>>>>>> 处理验证的 Handler
    from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
    from urllib.error import URLErrorusername = 'username'
    password = 'password'
    url = 'http://localhost:5000/'# 1. 实例化 HTTPPasswordMgrWithDefaultRealm 对象
    p = HTTPPasswordMgrWithDefaultRealm()
    # 2. 为该实例添加用户名和密码
    p.add_password(None, url, username, password)
    # 3. 通过 1 中的对象实例化 HTTPBasicAuthHandler 对象 ———— 得到一个处理验证的 Handler
    auth_handler = HTTPBasicAuthHandler(p)
    # 4. 通过上述 Handler 构建 Opener
    opener = build_opener(auth_handler)try:    # 5. 通过 open() 方法发送请求, 这里会自动完成验证result = opener.open(url)html = result.read().decode('utf-8')print(html)
    except URLError as e:print(e.reason)
    
    # >>>>>>>>>>>> 设置代理的 Handler
    from urllib.request import ProxyHandler, build_opener
    from urllib.error import URLError# 1. 实例化一个 ProxyHandler 对象, 其参数是一个字典, 键名为协议类型, 值为代理链接。
    proxy_handler = ProxyHandler({'http': "http://127.0.0.1:9743",'https': "https://127.0.0.1:9743"
    })
    # 2. 通过上面的 Handler 构建 Opener。
    opener = build_opener(proxy_handler)
    try:# 3. 通过 Opener 的 open() 方法发送请求。response = opener.open('https://www.baidu.com')print(response.read().decode('utf-8'))
    except URLError as e:print(e.reason)
    
    import http.cookiejar, urllib.request# >>>>>>>>>>>> 1. 生成 Cookies 文件
    filename = 'cookies.txt'# 1. 实例化 LWPCookieJar 对象
    cookie = http.cookiejar.LWPCookieJar(filename)
    # 2. 利用上述 cookie 实例构建 Handler
    handler = urllib.request.HTTPCookieProcessor(cookie)
    # 3. 利用上述 Handler 构建 Opener
    opener = urllib.request.build_opener(handler)
    # 4. 发送请求, 打印响应状态码
    response = opener.open('http://www.baidu.com')
    print(response.status)
    # 5. 调用 save() 方法保存 Cookies 到本地文件
    cookie.save(ignore_discard=True, ignore_expires=True)# >>>>>>>>>>>> 2. 读取并使用 Cookies (以 LWPCookieJar 格式为例)# 1. 实例化 LWPCookieJar 对象
    cookie = http.cookiejar.LWPCookieJar()
    # 2. load() 方法读取本地 Cookies 文件 (之前已经生成并保存)
    cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
    # 3. 构建 Handler
    handler = urllib.request.HTTPCookieProcessor(cookie)
    # 4. 构建 Opener
    opener = urllib.request.build_opener(handler)
    # 5. 发送请求, 此时就能得到百度的源代码了
    response = opener.open('http://www.baidu.com')
    print(response.read().decode('utf-8'))
    
  • 4. error.URLError

    由 request 模块产生的异常都可通过捕获 URLError 这个类来处理

    from urllib import error, requesttry:# 1. 视图打开一个不存在的页面response = request.urlopen('https://www.cuiqingcai.com/index.htm')
    except error.URLError as e:# 2. URLError 的属性 reason 用于返回错误的原因print(e.reason)
    
  • 5. error.HTTPError

    是 URLError 的子类,专门用于处理 HTTP 请求错误,有三个属性:code,reason 和 headers

    from urllib import error, requesttry:response = request.urlopen('https://www.cuiqingcai.com/index.htm')
    # 1. 先尝试捕获子类错误
    except error.HTTPError as e:# 输出 错误原因, HTTP状态码, 请求头print(e.reason, e.code, e.headers, sep="\n\n")
    # 2. 再尝试捕获父类错误
    except error.URLError as e:print(e.reason)
    else:print("Requested Successfully.")
    

    有时 reason 属性返回的未必是字符串,而是一个对象,见下例:

    import socket
    import urllib.request
    import urllib.errortry:# 1. 设置超时时间以强制抛出 timeout 异常response = urllib.request.urlopen('https://www.baidu.com', timeout=0.01)
    except urllib.error.URLError as e:print(type(e.reason))    # 打印结果: <class 'socket.timeout'>if isinstance(e.reason, socket.timeout):    # 判断 reason 的类型print('TIME OUT')
    
  • 6. parse 模块:用于实现 URL 各部分的抽取、合并及链接转换等。

    方法 介绍
    urlparse() 识别 url 并将其分成 6 个部分。返回结果是命名元组,支持属性名或index访问
    urlunparse() 接受一个长度必须为 6 的可迭代对象,以构造 url
    urlsplit() 与 urlparse() 相似,它将一个 url 拆分为 5 个部分(params 被合并到了 path 中)
    urlunsplit() 与 urlunparse() 类似,它接受一个长度必须为 5 的可迭代对象,以构造 url
    urljoin() 通过解析 base_url 对新链接进行补充
    urlencode() 将字典序列化为 GET 请求的参数
    parse_qs() 将 GET 请求参数 “反序列化” 为字典 (其中字典的值是列表形式)
    parse_qsl() 类似 parse_qs(),但它返回以元组为元素的列表
    quote() 可将 url 中的 “中文字符” 转化为 url 编码
    unquote() 用于 url 解码以还原 url 中的中文字符
    # 1. urlparse() 能识别 url 并将其分解为 6 个部分: scheme, netloc, path, params, query, fragment
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urlparseresult = urlparse("http://www.baidu.com/index.html;user?id=5#comment")
    print(result)
    # 返回结果是 ParseResult 类型的对象: ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')# 待解析的 url 中不含协议部分, 但在 scheme 参数中指定协议类型为 https
    result = urlparse("www.baidu.com/index.html;user?id=5#comment", scheme='https')
    print(result)
    # 返回结果中协议类型会采用 scheme 参数中指定的 https
    # Remark: 若待解析 url 中包含协议类型, 则 scheme 参数怎么指定都不影响解析结果# allow_fragments 参数指定为 False, 即忽略 fragment
    result = urlparse("http://www.baidu.com/index.html;user?id=5#comment", allow_fragments=False)
    print(result)
    # 此时返回结果中 fragment 部分为空, 而 #comment 被合并进了 query (前一个非空的组成部分)中# 返回结果 ParseResult 实际上是一个命名元组, 可以用 属性 & index 来访问:
    print(result.scheme, result[0], result.netloc, result[1], sep="\n")
    """
    运行结果为:
    http
    http
    www.baidu.com
    www.baidu.com
    """# 2. urlunparse() 方法接受一个长度(必须)为 6 的可迭代对象来构造 url
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urlunparsedata = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
    print(urlunparse(data))
    """
    运行结果为: http://www.baidu.com/index.html;user?a=6#comment
    """
    
    # 3. urlsplit() 方法与 urlparse() 相似, 它将一个 url 拆分为 5 个部分(params 被合并到了 path 中)
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urlsplitresult = urlsplit("http://www.baidu.com/index.html;user?id=5#comment")
    print(result, sep="\n")
    # 返回结果为 SplitResult 类型的对象: SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment'), 这其实也是一个命名元组, 可以通过 index & 属性 来访问:
    print(result.path, result[2], sep="\n")
    """
    运行结果为:
    /index.html;user
    /index.html;user
    """# 4. urlunsplit() 方法与 urlunparse() 类似, 它接受一个长度(必须)为 5 的可迭代对象, 以构造 url
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urlunsplitdata = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment']
    print(urlunsplit(data))
    """
    运行结果为: http://www.baidu.com/index.html?a=6#comment
    """
    
    # 5. urljoin() 会解析第一参数 base_url 以对新链接的缺失部分进行补充
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urljoinprint(urljoin("http://www.baidu.com", "FAQ.html"))
    print(urljoin("http://www.baidu.com", "https://cuiqingcai.com/FAQ.html"))
    print(urljoin("http://www.baidu.com/about.html", "https://cuiqingcai.com/FAQ.html"))
    print(urljoin("http://www.baidu.com/about.html", "https://cuiqingcai.com/FAQ.html?question=2"))
    print(urljoin("http://www.baidu.com?wd=abc", "https://cuiqingcai.com/index.php"))
    print(urljoin("http://www.baidu.com", "?category=2#comment"))
    print(urljoin("www.baidu.com", "?category=2#comment"))
    print(urljoin("www.baidu.com#comment", "?category=2"))
    """
    Remark: 通过上述例子可见 base_url 提供了三项内容 scheme, netloc 和 path若这 3 项在新链接中不存在, 则予以补充;若在新链接中存在, 则使用新链接的部分而 base_url 中的 params, query, fragment 是不起作用的。
    """
    
    # 6. urlencode() 可将字典序列化为 GET 请求的参数
    # -------------------------------------------------------------------------------------------
    from urllib.parse import urlencodeparams = {'name': 'GozenSanji', 'age': 17}
    base_url = "http://www.baidu.com?"
    url = base_url + urlencode(params)
    print(url)
    """
    运行结果为: http://www.baidu.com?name=GozenSanji&age=17
    """
    
    # 7. parse_qs() 将 GET 请求参数 “反序列化” 为字典 (其中字典的值是列表形式)
    # -------------------------------------------------------------------------------------------
    from urllib.parse import parse_qsquery = "name=GozenSanji&age=17"
    print(parse_qs(query))
    """
    运行结果为: {'name': ['GozenSanji'], 'age': ['17']}
    """# 8. parse_qsl() 类似 parse_qs(), 但它返回以元组为元素的列表
    # -------------------------------------------------------------------------------------------
    from urllib.parse import parse_qslquery = "name=GozenSanji&age=17"
    print(parse_qsl(query))
    """
    运行结果为: [('name', 'GozenSanji'), ('age', '17')]
    """
    
    # 9. quote() 可将 url 中的 "中文字符" 转化为 url 编码
    # -------------------------------------------------------------------------------------------
    from urllib.parse import quotekw = "城堡"
    url = "https://www.baidu.com/s?wd=" + quote(kw)    # 通过 quote() 对中文字符进行 url 编码
    print(url)
    """
    运行结果为: https://www.baidu.com/s?wd=%E5%9F%8E%E5%A0%A1
    """# 10. unquote() 用于 url 解码以还原 url 中的中文字符
    # -------------------------------------------------------------------------------------------
    from urllib.parse import unquoteurl = "https://www.baidu.com/s?wd=%E5%9F%8E%E5%A0%A1"
    print(unquote(url))
    """
    运行结果为: https://www.baidu.com/s?wd=城堡
    """
    
  • 7. robotparser 模块可以实现网站 Robots 协议的分析

    用到再说

  • 更方便的 Requests 库:

  • 1. 一个简单的例子

    # 1. 调用 get() 方法实现 GET 请求
    # -------------------------------------------------------------------------------------------
    import requestsr = requests.get("https://www.baidu.com")
    print(type(r))            # 返回一个 Response 类型的对象
    print(r.status_code)    # 状态码
    print(type(r.text))        # 响应体类型为 str
    print(r.text)           # 响应体内容
    print(r.cookies)        # cookies (类型为 RequestsCookieJar)
    

    除了 GET 请求,还有下面的:

    # 2. 一行代码实现其他类型的请求
    # -------------------------------------------------------------------------------------------
    import requestsr1 = requests.post("http://httpbin.org/post")
    r2 = requests.put("http://httpbin.org/put")
    r3 = requests.delete("http://httpbin.org/delete")
    r4 = requests.head("http://httpbin.org/get")
    r5 = requests.options("http://httpbin.org/get")
    
  • 2. Get 请求

    # 1. 在 get 请求中添加参数
    # -------------------------------------------------------------------------------------------
    import requests# 1. 以字典形式构造参数
    data = {"name": "victorique", "age": 12}
    # 2. 将字典传递给 params 参数
    r = requests.get('http://httpbin.org/get', params=data)
    # 3. 此时请求信息中就可以看到传递的参数了
    print(r.text)
    

    进阶の例子:

    # 1. 抓取网页(知乎页面里“热门收藏夹”下的一些title)
    # -------------------------------------------------------------------------------------------
    import requests
    import re# 1. 指定 headers 中的 UA
    headers = {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
    }
    # 2. 发送带 headers 参数的 Get 请求
    r = requests.get("https://www.zhihu.com/explore", headers=headers)
    # 3. 创建正则表达式对象(带修饰符)
    pattern = re.compile('<a class="ExploreCollectionCard-contentTitle".*?data-za-detail-view-id.*?>(.*?)</a>', re.S)
    # 4. 通过 findall 方法进行正则匹配
    titles = re.findall(pattern, r.text)
    print(titles)# 2. 抓取二进制数据(图片,音频,视频等)
    # -------------------------------------------------------------------------------------------# 1. 请求 github 网站图标
    r = requests.get("https://github.com/favicon.ico")
    print(r.text)    # 以 str 类型打印, 显示乱码
    print(r.content)    # 以 bytes 类型打印
    # 2. 以二进制写的形式打开
    with open('favicon.ico', 'wb') as f:# 3. 写入二进制数据, 得到网站图标文件f.write(r.content)
    
  • 3. POST 请求

    import requests# 1. 构造字典形式的参数
    data = {'name': 'GozenSanji', 'age': 17}
    # 2. 发送带有参数的 POST 请求
    r = requests.post("http://httpbin.org/post", data=data)
    # 3. 传递的参数在 “form” 当中
    print(r.text)
    
  • 4. 响应

    # 发送请求后, 得到响应, 下面查看其各种属性
    import requestsheaders = {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
    }
    r = requests.get("http://jianshu.com", headers=headers)
    # 1. 状态码
    print(type(r.status_code), r.status_code, sep=" ~~~ ")
    # 2. 响应头
    print(type(r.headers), r.headers, sep=" ~~~ ")
    # 3. Cookies
    print(type(r.cookies), r.cookies, sep=" ~~~ ")
    # 4. url
    print(type(r.url), r.url, sep=" ~~~ ")
    # 5. 请求历史
    print(type(r.history), r.history, sep=" ~~~ ")
    
  • 5. 高级用法:

    import requests
    # 1. 文件上传
    # -------------------------------------------------------------------------------------------# 0. 注意这个 files 的写法
    files = {'file': open('favicon.ico', 'rb')}
    # 1. 发送 POST 请求时, 指定 files 参数以上传文件
    r = requests.post("http://httpbin.org/post", files=files)
    # 2. 在 files 字段下的内容证明成功上传了文件
    print(r.text)# 2. 获取和设置 Cookies
    # -------------------------------------------------------------------------------------------
    r = requests.get("https://www.baidu.com")
    # 1. 直接通过 cookies 属性获取 Cookies
    print(r.cookies)
    # 2. 可对 Cookies 遍历解析
    for k, v in r.cookies.items():print(f"{k} = {v}")# 3. 在 headers 中设置好 Cookie (以维持登录状态)
    headers = {'Cookie': 'SESSIONID=yGSmUltPNjOrmaNJ36mdO9M5ZugNuhex2zE2ceZqqL2; JOID=UlgQBU4M0Np7HR0XNwo1DfeUepkjL_b6Wzs-MRcq8_xbPTs0EXy43yIYGBE3EjupzXIINfypdNYHdDZvaOFdvUM=; osd=W1AdAUgF2Nd_GxQfOg4zBP-Zfp8qJ_v-XTI2PBMs-vRWOT09GXG82SsQFRUxGzOkyXQBPfGtct8PeTJpYelQuUU=; _zap=21f4fd90-7f8b-4394-8cec-cdf3218d2566; d_c0="AABdnthhWRGPTsDP-usAf5MCAuo-_GX0fmc=|1590836114"; _ga=GA1.2.1794552939.1590836116; _gid=GA1.2.646135605.1594178659; _xsrf=db959aea-df00-4fe2-8565-23dde1c4cfa7; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1593754262,1593754407,1594178659,1594191473; capsion_ticket="2|1:0|10:1594191476|14:capsion_ticket|44:MzBlMDVmOWE3MjhjNDhjNjljMDIxZDJkOTRmZGIwOWY=|8f1100ba056a2e7b86d74471116f04e330f42f0c2a07159f5e100f7db3426dea"; z_c0="2|1:0|10:1594191483|4:z_c0|92:Mi4xeEt2WUJBQUFBQUFBQUYyZTJHRlpFU1lBQUFCZ0FsVk5lN3p5WHdDM0lLWDdDVjZPZ24xaHVVME9HQWJzMmpvLTJ3|18a961f2133a663da09762645cc9a931c128431774c01a347c919f1e10b73531"; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1594191483; q_c1=3e59bd711414449b965e3cc4b7201261|1594191484000|1594191484000; KLBRSID=d017ffedd50a8c265f0e648afe355952|1594191512|1594191473','Host': 'www.zhihu.com','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
    # 4. 发送 get 请求时传递 headers 参数
    r = requests.get("https://www.zhihu.com", headers=headers)
    # 5. 响应结果中包含登录后的内容, 说明登录成功
    print(r.text)
    
    # 3. 利用 Session 对象维持会话
    # -------------------------------------------------------------------------------------------
    import requests# 1. 首次请求测试网址时, 设置了 cookie, 其名称为 number, 内容为 123456789
    requests.get("http://httpbin.org/cookies/set/number/123456789")
    # 2. 再请求测试网址, 此网址可以获取当前 Cookies
    r = requests.get('http://httpbin.org/cookies')
    # 3. 但这样并不能获取到设置的 Cookies
    print(r.text)
    
    # 接下来利用 Session 进行尝试
    import requests
    # 1. 实例化一个 Session 对象
    s = requests.Session()
    # 2. 请求测试网址并设置 cookie
    s.get("http://httpbin.org/cookies/set/number/123456789")
    # 3. 通过 Session 再次请求测试网址获取当前 Cookies
    r = s.get('http://httpbin.org/cookies')
    # 4. 这里成功获取到了前一次请求时设置的 cookie
    print(r.text)# Remark: 1. 使用 requests.post() 方法登录某网站后, 再使用 requests.get() 方法获取登录后的信息, 这相当于打开了两个浏览器, 是两个无关的会话, 因此这样无法得到登陆后的信息。   2. 利用 Session, 可以做到模拟同一个会话而不用担心 Cookies 的问题, 它通常用于模拟登录成功后再进行下一步操作。
    

    在发送 HTTP 请求时,会自动检查 SSL 证书,因而会有出现证书验证错误的结果,此时可通过设置 verify 参数不进行证书验证。

    # 4. verify 参数控制是否验证证书
    # -------------------------------------------------------------------------------------------
    import requests
    from requests.packages import urllib3# 1. 设置忽略警告 (注释掉我试试看)
    urllib3.disable_warnings()
    # 2. 发送 get 请求时将 verify 设置为 False (默认为 True)
    response = requests.get("https://www.12306.cn", verify=False)
    print(response.status_code)# 5. 通过 proxies 参数设置代理
    # -------------------------------------------------------------------------------------------
    # 1. 构造代理参数字典
    proxies = {'http': 'http://host:port','https': 'https://host:port'
    }    # 这只是个模板哦
    """
    若代理需要使用 HTTP Basic Auth, 可以像下面这样设置代理:
    proxies = {'http': 'http://user:password@host:port'}
    """
    # 2. 发送 get 请求时通过 proxies 参数传入代理
    requests.get("https://taobao.com", proxies=proxies)# 6. 通过 timeout 参数设置超时时间
    # -------------------------------------------------------------------------------------------
    # 1. 通过指定 timeout 参数, 将超时时间设置为 1s, 若 1s 内无响应则抛出异常
    r = requests.get("https://www.taobao.com", timeout=1)
    # 2. 将 timeout 改为 0.01 看看会怎么样?
    print(r.status_code)
    # Remark: 想要永久等待, 可以设置 timeout=None 或者干脆不设置该参数。# 7. 通过 auth 参数实现身份认证
    # -------------------------------------------------------------------------------------------
    # 1. 这里只是一个测试 url, auth 参数接受一个用户名和密码的元组
    r = requests.get('http://localhost:5000', auth=('username', 'password'))
    # 2. 发送请求时将自动认证, 认证成功则返回状态码为 200
    print(r.status_code)
    
    # 8. 将请求当作独立的对象来看待: Prepared Request
    # -------------------------------------------------------------------------------------------
    from requests import Request, Sessionurl = "http://httpbin.org/post"
    data = {'name': 'victorique'}
    headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}# 1. 实例化一个 Session 对象
    s = Session()
    # 2. 用 url, data, headers 构造一个 Request 对象
    req = Request('POST', url, data=data, headers=headers)
    # 3. 通过 Session 的 prepare_request() 方法将 Request 对象转换为 Prepared Request 对象
    prepared = s.prepare_request(req)
    # 4. 通过 Session 的 send() 方法发送 Prepared Request 实例
    r = s.send(prepared)
    # 5. 从结果可以看到这种方式同样达到了 POST 请求的效果
    print(r.text)
    
  • 有用的 正则表达式

    正则表达式是处理字符串的强大工具,它能实现字符串的 检索、替换、匹配

    书中 表3-2(on Page 140)列出了常用的匹配规则供随时查阅。

  • 1. match() 方法

    match() 会尝试从字符串的起始位置匹配正则表达式,若匹配则返回匹配成功的结果;若不匹配则返回 None。

    下面看一个简单的例子:

    import re# 1. 声明一个 String 并打印其长度
    content = "Hello 123 4567 World_This is a Regex Demo"
    print(len(content))
    # 2. ^匹配字符串开头, \s匹配空白字符, \d匹配数字, \d\d\d\d = \d{4}, \w{10}匹配10个字母及下划线
    regex = '^Hello\s\d\d\d\s\d{4}\s\w{10}'
    # 3. match() 的第一个参数为正则表达式, 第二个参数为目标字符串
    result = re.match(regex, content)
    # 4. 返回结果为 re.Match 对象
    print(result)
    # 5. group() 方法输出匹配到的内容, span() 方法输出匹配的下标范围
    print(result.group(), result.span(), sep="\n")
    

    以下为更实用的示例:

    # 1. 使用 () 进行目标匹配
    # -------------------------------------------------------------------------------------------
    import recontent = "Hello 1234567 World_This is a Regex Demo"
    regex = "^Hello\s(\d+)\sWorld"    # 目标是7个数字
    result = re.match(regex, content)
    # group 将输出完整的匹配结果, 而 group(i) 将输出第 i 个被 () 包围的匹配结果
    print(result.group(), result.group(1), result.span(), sep="\n")# 2. 通用匹配 .*
    # -------------------------------------------------------------------------------------------
    content = "Hello 1234567 World_This is a Regex Demo"
    regex = "^Hello.*Demo$"    # 以 Hello 开始, 以 Demo 结束, 中间匹配任意字符
    result = re.match(regex, content)
    print(result.group(), result.span(), sep="\n")# 3. 贪婪与非贪婪
    # -------------------------------------------------------------------------------------------
    content = "Hello 1234567 World_This is a Regex Demo"
    regex = "^He.*(\d+).*Demo$"    # 贪婪匹配 .* 将匹配尽可能多的字符
    result = re.match(regex, content)
    print(result.group(1), sep="\n")    # 这里只能匹配到一个数字7,想想为什么?regex = "^He.*?(\d+).*Demo$"    # 非贪婪匹配 .*? 将匹配尽可能少的字符, 推荐使用!
    result = re.match(regex, content)
    print(result.group(1), sep="\n")    # 这里可以匹配到全部7个数字# 再看一个例子:
    content = 'http://weibo.com/comment/kEraCN'
    result1 = re.match('^http.*?comment/(.*?)', content)    # 目标匹配为空
    result2 = re.match('^http.*?comment/(.*)', content)    # 目标匹配到 kEraCN
    print(f"result1: {result1.group(1)}", f"result2: {result2.group(1)}", sep="\n")# 4. 修饰符
    # -------------------------------------------------------------------------------------------
    content = '''Hello 1234567 World_This
    is a Regex Demo'''    # 这是一个带有换行符的字符串
    result = re.match("^He.*(\d+).*?Demo$", content)
    # 匹配失败返回 None, 这是因为 . 匹配的是“除换行符之外的任意字符”, 当遇到换行符时 .*? 就不能匹配了
    print(result)# 使用修饰符 re.S 使 . 匹配 “包括换行符在内的所有字符”
    result = re.match("^He.*?(\d+).*?Demo$", content, re.S)
    # 此时就可以成功匹配到整个字符串了
    print(result)
    # Remark: 表 3-3 on Page 145 给出了其他常用修饰符以供参考# 5. 转义匹配
    # -------------------------------------------------------------------------------------------
    content = "(百度)www.baidu.com"
    # 当遇到用于正则匹配模式的特殊字符时, 在前面加反斜线转义一下即可
    result = re.match('\(百度\)www\.baidu\.com', content)
    # 经反斜线实现转义后, 这里成功匹配了上述字符串
    print(result)
    
  • 2. search() 方法

    match 方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了,而<span style='color:orange;background: ;font-size: ;font-family: ;'> search 方法则会扫描整个字符串,并返回第一个成功匹配的结果。</span>
    
    # search() 可以匹配子字符串
    # ------------------------------------------------------------------------------------------
    import recontent = "EXTRA STRING Hello 1234567 World_This is a Regex Demo EXTRA STRING"
    result = re.search('Hello.*?(\d+).*?Demo', content)
    # 这里成功匹配到了除去开头和结尾的 EXTRA STRING 部分的字串
    print(result.group())
    

    下面是一个匹配网页源代码的例子:

    import rehtml = '''
    <div id="songs-list"><h2 class="title">经典老歌</h2><p class="introduction">经典老歌列表</p><ul id="list" class="list-group"><li data-view="2">一路上有你</li><li data-view="7"><a href="/2.mp3" singer="任贤齐">沧海一声笑</a></li><li data-view="4" class="active"><a href="/3.mp3" singer="秦齐">往事随风</a></li><li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li><li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li><li data-view="5"><a href="/6.mp3" singer="邓丽君">但愿人长久</a></li></ul>
    </div>
    '''
    # 这里尝试匹配 class="active" 的节点下的子节点中的歌手与歌曲名
    regex = '<li.*?active.*?singer="(.*?)">(.*?)</a>'
    result = re.search(regex, html, re.S)    # 注意加上修饰符以应对换行符的匹配
    # 成功输出歌手名与歌曲名
    print(result.group(1), result.group(2), sep="\n")
    
  • 3. findall() 方法

    相对于 search 方法返回第一个成功匹配的内容,findall 方法会 搜索整个字符串,然后返回匹配正则表达式的所有内容。

    import re# 对同样的 html 这里尝试获取所有 a 节点的超链接, 歌手和歌名
    regex = '<a href="(.*?)".*?singer="(.*?)".*?>(.*?)</a>'
    result = re.findall(regex, html, re.S)
    # 若匹配成功, 则结果为列表类型
    print(type(result))for each in result:print(f"超链接: {each[0]};  歌手: {each[1]};  歌曲名: {each[2]}")
    
  • 4. sub() 方法

    sub 方法可以将字符串中与正则表达式匹配的部分替换为其他内容:
    
    import re# 1. 替换字符串中的数字为												

    Python 3 网络爬虫 个人笔记 (未完待续)相关推荐

    1. linux排查网络问题,Linux网络问题排查(未完待续)

      最近在做的实验,需要同时保持大量的TCP连接,大概在3K的连接数,但是会在一些时刻突然有大量连接断开,等发现的时候也很难排查原因. 主要考虑有三方面的原因,1是网络,2是内存CPU,3是实验本身的代码 ...

    2. TS学习笔记 ---未完待续....

      TS学习笔记 1 .ts文件与.tsx文件有什么区别 2.使用TS之前需要配置 3.TS特性 泛型和类型注解有什么区别? 3.什么是泛型参数? 4.函数.类.接口有什么区别? 4.1 一个class不 ...

    3. JNI方面的笔记(未完待续)

      Microsoft Windows [版本 6.1.7600] 版权所有 (c) 2009 Microsoft Corporation.保留所有权利. C:\Users\toto>javah 用 ...

    4. Python标准库-string模块《未完待续》

      >>> import string >>> s='hello rollen , how are you ' >>> string.capwords ...

    5. Java并发笔记-未完待续待详解

      为什么需要并行?– 业务要求– 性能并行计算还出于业务模型的需要– 并不是为了提高系统性能,而是确实在业务上需要多个执行单元.– 比如HTTP服务器,为每一个Socket连接新建一个处理线程– 让不同 ...

    6. pythonb超分辨成像_Papers | 超分辨 + 深度学习(未完待续)

      1. SRCNN 1.1. Contribution end-to-end深度学习应用在超分辨领域的开山之作(非 end-to-end 见 Story.3 ). 指出了超分辨方向上传统方法( spar ...

    7. 网页爬虫python代码_《用python写网络爬虫》完整版+源码

      原标题:<用python写网络爬虫>完整版+源码 <用python写网络爬虫>完整版+附书源码 本书讲解了如何使用Python来编写网络爬虫程序,内容包括网络爬虫简介,从页面中 ...

    8. python网络爬虫学习笔记(6)动态网页抓取(一)知识

      文章目录 网络爬虫学习笔记(2) 1 资料 2 笔记 2-1 动态抓取概述 2-2 通过浏览器审查元素解析真实网页地址 2-3 网页URL地址的规律 2-4 json库 2-5 通过Selenium模 ...

    9. python爬虫requests源码链家_python爬虫——爬取链家房价信息(未完待续)

      爬取链家房价信息(未完待续) items.py # -*- coding: utf-8 -*- # Define here the models for your scraped items # # ...

    10. Python学习网络爬虫--转

      原文地址:https://github.com/lining0806/PythonSpiderNotes Python学习网络爬虫主要分3个大的版块:抓取,分析,存储 另外,比较常用的爬虫框架Scra ...

    最新文章

    1. 关于Beta分布、二项分布与Dirichlet分布、多项分布的关系
    2. CF1082E Increasing Frequency
    3. Spring boot使用Bootstrap
    4. 前端工具:推荐几款UI设计师好用的设计软件
    5. 搭建bitwarden_Docker轻松部署Bitwarden私有密码管理系统服务
    6. Spring模板对象
    7. 单用户修改root密码--Ubuntu 16.04.3 LTS
    8. python数据容器专题
    9. JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
    10. 计算机信息管理自荐信个人简历,计算机信息专业英文自荐信
    11. Fragment与Activity
    12. SQL必知必会 课后题答案
    13. 星环分析型数据库Inceptor中database link的使用总结
    14. Kettle文件下载
    15. linux下查看共享文件夹,在Linux下查看共享文件夹
    16. 数字信号处理第二章:Z变换及离散时间系统系统分析
    17. Bypass注入(WAF绕过)
    18. 【交易架构day6】有赞订单交易系统的演进之路——如何存储海量订单数据
    19. Linus最高产,2021 Linux内核开发统计出炉
    20. 安庆集团-冲刺日志(第三天)

    热门文章

    1. 集成电路实践----D触发器
    2. 查看浏览器保存的密码
    3. oracle 英文 简历,英文优秀个人简历模板范文
    4. 用CE修改植物大战僵尸阳光值
    5. c语言实现费诺编码csdn,香农编码 哈夫曼编码 费诺编码的比较
    6. 计算机病毒note01
    7. 【Android】全网最详细的Android入门基础教程,零基础速领
    8. 免费的客户订单及商品管理系统
    9. java版flashplayer下载安装_mac版flash player
    10. 热门!实用!游戏rpg制作素材网站推荐!