爬虫1——urllib的使用

一、什么是爬虫

1、爬虫Spider的概念

爬虫用于爬取数据,又称之为数据采集程序。

爬取的数据来源于网络,网络中的数据可以是由WEB服务器(Nginx/Apache),数据库服务器(MySQL、Redis),索引库(ElastichSearch),大数据(Hbase/Hive),视频/图片库(FTP),云存储(OSS)等提供。

爬取的数据是公开的,非盈利的。

2、Python爬虫

使用Python编写的爬虫脚本(程序)可以完成定时,定量,指定目标(web站点)的数据爬取,主要使用多(单)线程/进程、网络请求库、数据解析、数据存储、任务调度等相关技术。

Python爬虫工程师,可以完成接口测试,功能性测试,性能测试,集成测试。

二、爬虫与WEB后端服务之间的关系

爬虫使用网络请求库,相当于客户端请求,Web后端服务根据请求响应数据。

爬虫即向Web服务器发起HTTP请求,正确的接收响应数据,然后根据数据的类型(Content-Type)进行数据的解析及存储。

爬虫程序在发起请求前,需要伪造一个浏览器(User-Agent指定头),然后再向服务器发起请求,响应200的成功率高很多。

三、Python爬虫技术的相关库

1、网络请求

  • urllib
  • requests
  • selenium(UI自动测试,动态js渲染)
  • appium(手机APP的爬虫或UI测试)

2、数据解析

  • re正则
  • xpath
  • bs4
  • json

3、数据存储

  • pymysql
  • mongodb
  • elasticsearch

4、多任务

  • 多线程(threading)、线程队列 queue
  • 协程(asynio、gevent/eventlet)

5、爬虫框架

  • scrapy
  • scrapy-redis分布式(多机爬虫)

四、常见反爬虫的策略

  • UA(User-Agent)策略
  • 登录限制(Cookie)策略
  • 请求频次(IP代理)策略
  • 验证码(图片-云打码,点触验证、滑块)策略
  • 动态js策略(Selenium/Splash/api接口)策略

五、爬虫库urllib

1、urllib.request模块

1.1、简单请求

from urllib.request import urlopen

# 发起网络请求
resp = urlopen("http://www.hao123.com")
assert resp.code == 200
print("请求成功")
# 保存请求的网页
# f变量接收open()函数返回对象的__enter__()返回的就结果

   with open("hao123.html", "wb") as f: f.write(resp.read())

urlopen(url, data=None)可以直接发起url请求,如果data不为空时,默认是POST请求,反之为GET请求。

resp是http.client.HTTPResponse类对象

1.2、带请求头的请求

"""
初次使用urllib实现爬虫的数据请求
urllib.request.urlopen(url)  发起get请求
urllib.parse.quote()   讲中文进行url编码
urllib.request.urlretrieve(url, filename)  下载url保存到filename
"""

from urllib.request import urlopen, urlretrieve, Request
from urllib.parse import quote

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

def search_baidu(wd='李志'):
    # 网络请求资源接口(url)
    url = 'https://www.baidu.com/s?wd=%s'

    # 生成请求对象,封装请求的url和头header
    request = Request(url % quote(wd), headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
        'Cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZoRWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWljaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX; BD_UPN=12314753; BD_HOME=1; H_PS_PSSID=30974_1429_21108_30997_30824_30717; delPer=0; BD_CK_SAM=1; PSINO=6; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; COOKIE_SESSION=93270_0_5_4_10_6_0_0_4_3_0_3_93360_0_4_0_1583674230_0_1583674226%7C9%230_2_1577625718%7C1; sug=3; sugstore=0; ORIGIN=0; bdime=0; H_PS_645EC=ee56%2Bh2%2FYYj4EN%2FXrG%2FdO5beNAv52Z9Yz4fZg21AWgMroxtYWtP17XRR1VM'
    })
    response = urlopen(request)
    assert response.code == 200
    print("请求成功")

    # 读取响应的数据
    bytes_ = response.read()
    with open('%s.html' % wd, "wb") as file:
        file.write(bytes_)

 2、urllib.parse模块

此模块有两个核心函数:

quote()仅对中文字符穿进行url编码

urlencode()可以针对一个字典中所有的values进行编码,然后转成key=value&key=value字符串。

from urllib.parse import quote
from urllib.parse import urlencode
quote("李志")
'%E6%9D%8E%E5%BF%97'
urlencode({"姓名":"李志"})
'%E5%A7%93%E5%90%8D=%E6%9D%8E%E5%BF%97'

 六、百度翻译的实现

'''
应用:百度翻译
urllib.request.Request
urllib.request.urlopen()
urllib.parse.urlencode()
发起post请求
'''
import json
from urllib.parse import urlencode
from urllib.request import Request, urlopen


url = 'https://fanyi.baidu.com/sug'

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    'cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; '
              'BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZo'
              'RWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWl'
              'jaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX;'
              ' to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22valu'
              'e%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1;'
              ' FANYI_WORD_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; delPer=0; PSINO=6; '
              'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; '
              'BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; H_PS_PSSID=30974_1429_21108_30997_30824; '
              'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1581948391,1583753885; '
              'from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22'
              '%7D%2C%7B%22value%22%3A%22dan%22%2C%22text%22%3A%22%u4E39%u9EA6%u8BED%22%7D%2C%7B%2'
              '2value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; Hm_lpvt_64ecd82404c51e03dc91cb'
              '9e8c025574=1583753974; __yjsv5_shitong=1.0_7_f938cb5bed75810c7f54daa26e4d74d416c7_300_1583753976124_'
              '219.145.32.239_2b22827f;yjs_js_security_passport=afa2db6dc7814c5d0875abbf087495d6b1b9b20f_1583753976_js'
}


def fanyi(kw):
    data = {
        'kw': kw
    }
    # Request()中的data参数是byte类型
    # data不为空时,就是post请求
    req = Request(url, data=urlencode(data).encode("utf-8"))
    resp = urlopen(req)
    assert resp.code == 200
    json_data = resp.read()  # byte
    content_encode = resp.getheader("Content-Type")
    content_encode = "utf-8" if content_encode is None else content_encode.split("=")[-1]
    return json.loads(json_data.decode(content_encode))  # loads函数将json字串变为字典


if __name__ == '__main__':
    print(fanyi("orange"))

七、GET请求多个页面

"""
复杂的get请求,多页面请求下载
"""
import random
import time
from urllib.request import Request, urlopen
from urllib.parse import urlencode


url = "https://www.baidu.com/s?"
params = {
    'wd': '',
    'pn': 0   # 0, 10, 20, 30...= (n-1)*10
}

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    'cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; '
              'BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZo'
              'RWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWl'
              'jaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX;'
              ' to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22valu'
              'e%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1;'
              ' FANYI_WORD_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; delPer=0; PSINO=6; '
              'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; '
              'BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; H_PS_PSSID=30974_1429_21108_30997_30824; '
              'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1581948391,1583753885; '
              'from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22'
              '%7D%2C%7B%22value%22%3A%22dan%22%2C%22text%22%3A%22%u4E39%u9EA6%u8BED%22%7D%2C%7B%2'
              '2value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; Hm_lpvt_64ecd82404c51e03dc91cb'
              '9e8c025574=1583753974; __yjsv5_shitong=1.0_7_f938cb5bed75810c7f54daa26e4d74d416c7_300_1583753976124_'
              '219.145.32.239_2b22827f;yjs_js_security_passport=afa2db6dc7814c5d0875abbf087495d6b1b9b20f_1583753976_js'
}

def pages_get(wd):
    params['wd'] = wd
    for page in range(1, 101):
        params['pn'] = (page-1) * 10

        page_url = url + urlencode(params)
        resp = urlopen(Request(page_url, headers=headers))
        assert resp.code == 200
        filename = "baidu_pages/%s-%s.html" % (wd, page)
        time.sleep(random.random())
        with open(filename, 'wb') as f:
            bytes_ = resp.read()
            f.write(bytes_)
            print('下载%s页成功' % page)



if __name__ == '__main__':
    pages_get("李志")

八、Handler处理器

request对象不能携带cookie,也不能使用代理,所以引入了Handler处理器、自定义Opener。

1、步骤

创建Handler对象

handler = urllib.request.HTTPHandler()

创建opener对象

opener= urllib.request.build_opener(handler)

创建Request对象

request = urllib.request.Request(url=url,headers=headers

发送Reques请求

response = opener.open(request)

九、cookie库

1、cookie库能干啥?

自动帮我们保存登陆的cookie信息

2、cookie库配置

创建一个CookieJar对象

from http.cookiejar import CookieJar
cookie = cookiejar.CookieJar()

使用cookiejar对象,创建一个handler对象

handler = urllib.request.HTTPCookieProcessor(cookie)

使用handler创建一个opener

opener = urllib.request.build_opener(handler)

通过opener登录

handler会自动的保存登录之后的cookie

import urllib.request
import http.cookiejar as cookiejar


post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=20182122180'

data = {
    'rkey':'1c7df63368df7ce73c234de26178ec11',
    'password':'19870115',
    'origURL':'http://www.renren.com/home',
    'key_id':'1',
    'icode':'',
    'f':'http://www.renren.com/224549540',
    'email':'dqsygcz@126.com',
    'domain':'renren.com',
    'captcha_type':'web_login',
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
    'Referer': 'http://www.renren.com/SysHome.do'
}

# 转换字节
data = urllib.parse.urlencode(data).encode('utf-8')
# 定制请求对象
request = urllib.request.Request(url=post_url, headers=headers, data=data)
# 创建cookie对象
cookie = cookiejar.CookieJar()
# 创建handler对象
handler = urllib.request.HTTPCookieProcessor(cookie)
# 创建opener对象
opener = urllib.request.build_opener(handler)
# 使用opener对象发送请求
response = opener.open(request)
print(response.getcode())

十、代理服务器

1、什么是代理服务器

一种重要的服务器安全功能,它的工作主要在开放系统互联(OSI)模型的会话层,从而起到防火墙的作用

FQ,是指绕过相应的IP封锁、内容过滤、域名劫持、流量限制等。

2、代理的常用功能

突破自身IP访问限制,访问国外站点。

访问一些单位或团体内部资源

提高访问速度,通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。

隐藏真实IP。

3、代码配置

创建Reuqest对象

创建ProxyHandler对象

用handler对象创建opener对象

使用opener.open函数发送请求

# 创建代理handler对象
handler = urllib.request.ProxyHandler(proxies={'http':'114.212.80.2:3128'})

# 创建opener 
opener = urllib.request.build_opener(handler)
# opener.open 替代 urllib.request.urlopen
response = opener.open(request)

with open('ipp.html','wb') as fp:
    fp.write(response.read())

 

posted @ 2020-03-09 22:10  李大鹅  阅读(955)  评论(0编辑  收藏  举报