python爬虫

爬虫概念:按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
                  通俗的来说就是:就是爬虫可以模拟浏览器的行为做你想做的事,订制化自己搜索和下载的内容,并实现自动化的操作。


爬虫实现: 实现爬虫技术的编程环境有很多种,Java,Python,C++等都可以用来爬虫

爬虫包含6个模块:

  • url管理器
  • download下载器
  • parser解析器
  • output导出数据
  • crawler爬虫调度器
  • useragent代理池

爬虫学习知识点:
1、首先学会基本的Python语法知识
2、学习Python爬虫常用到的几个重要内置库urllib, http等,用于下载网页
3、学习正则表达式re、BeautifulSoup(bs4)、Xpath(lxml)等网页解析工具
4、开始一些简单的网站爬取(博主从百度开始的,哈哈),了解爬取数据过程
5、了解爬虫的一些反爬机制,header,robot,时间间隔,代理ip,隐含字段等
6、学习一些特殊网站的爬取,解决登录、Cookie、动态网页等问题
7、了解爬虫与数据库的结合,如何将爬取数据进行储存
8、学习应用Python的多线程、多进程进行爬取,提高爬虫效率
9、学习爬虫的框架,Scrapy、PySpider等
10、学习分布式爬虫(数据量庞大的需求)

一个请求过程在浏览器输入网址搜索后----->DNS服务器进行域名解析----->找到对应服务器并通过GET或POST方法请求数据----->
-       ---->若请求成功,我们就得到了我们想看到的网页----->
                        ---->若请求不成功,服务器会返回给我们请求失败的状态码,常见到的503,403等


爬虫的原理:Python爬虫通过URL管理器,判断是否有待爬URL,如果有待爬URL,通过调度器进行传递给下载器,下载URL内容,并通过调度器传送给解析器,解析URL内容,并将价值数据和新URL列表通过调度器传递给应用程序,并输出价值信息的过程;

爬虫的基本流程,主要可以分为三部分:

  • 获取网页
  • 解析网页(提取数据)
  • 存储数据

爬虫相关的包与工具

  • 一些爬虫工具:Octoparse、Cyotek WebCopy、HTTrack、Getleft、Scraper等;
  • 获取网页:request、urllib、selenium | 多进程多线程抓取、登陆抓取、突破IP封锁、服务器抓取;
  • 解析网页:re正则表达式、BeautifulSoup、Ixml | 解决中文乱码
  • 存储数据:存入txt文件、存入csv文件 | 存入数据库


python请求:urllib库:向服务器发出请求并获得网页的功能
Python2.x中使用的urllib2和urllib库,而Python3.x中合并成一个唯一的urllib库。
python属性:error,parse,request,response。

1、Error:“Exception classesraised by urllib.”----就是由urllib举出的exception类
2、Parse:“Parse (absolute andrelative) URLs.”----解析绝对和相对的URLs
3、Request:“An extensiblelibrary for opening URLs using a variety of protocols”
----用各种协议打开URLs的一个扩展库
4、Response:“Response classesused by urllib.”----被urllib使用的response类

一个简单例子:获取python网页

import urllib.request
response = urllib.request.urlopen('http://python.org/')
result = response.read().decode('utf-8')
print(result)

其中urlopen方法

def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TI
MEOUT,*, cafile=None, capath=None,
cadefault=False, context=None):

参数介绍:
url:即是我们输入的url网址,(如:http://www.xxxx.com/);
data: 是我们要发给服务器请求的额外信息(比如登录网页需要主动填写的用户信息)。如果需要添加data参数,
            那么是POST请求,默认无data参数时,就是GET请求;
            一般来讲,data参数只有在http协议下请求才有意义
           data参数被规定为byte object,也就是字节对象
           data参数应该使用标准的结构,这个需要使用urllib.parse.urlencode()将data进行 转换,
           而一般我们把data设置成字典格式再进行转换即可;data在以后实战中会介绍如何使用
timeout:是选填的内容,定义超时时间,单位是秒,防止请求时间过长,不填就是默认的时间;
cafile:是指向单独文件的,包含了一系列的CA认证 (很少使用,默认即可);
capath:是指向文档目标,也是用于CA认证(很少使用,默认即可);
cafile:可以忽略
context:设置SSL加密传输(很少使用,默认即可);

打开链接后其他操作:

geturl(): 返回URL,用于看是否有重定向。
result = response.geturl()
结果: https://www.python.org/
info():返回元信息,例如HTTP的headers。
       result = response.info()
结果:
x-xss-protection: 1; mode=block
X-Clacks-Overhead: GNU Terry Pratchett
...
Vary: Cookie
Strict-Transport-Security: max-age=63072000;includeSubDomains
getcode():返回回复的HTTP状态码,成功是200,失败可能是503等,可以用来检查代理IP的可使用性。
result = response.getcode()
结果:200
Request方法
class Request:
      def __init__(self, url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None):


参数介绍:
url,data和上面urlopen中的提到的一样。
headers是HTTP请求的报文信息,如User_Agent参数等,它可以让爬虫伪装成浏览器而不被服务器发现你正在使用爬虫。
origin_reg_host, unverifiable, method等不太常用


headers很有用,有些网站设有反爬虫机制,检查请求若没有headers就会报错,
因此为保证爬虫的稳定性,基本每次都会将headers信息加入进去,这是反爬的简单策略之一

import urllib.request
headers = {'User_Agent': ''}
response = urllib.request.Request('http://python.org/', headers=headers)
html = urllib.request.urlopen(response)
result = html.read().decode('utf-8')
print(result)

error的使用:error属性里面主要包括了两个重要的exception类,URLError类和HTTPError类。

1. URLError类

def __init__(self, reason, filename=None):
    self.args = reason,
    self.reason = reason
    if filename is not None:
        self.filename = filename
URLError类是OSError的子类,继承OSError,没有自己的任何行为特点,但是将作为error里面所有其它类型的基类使用。
URLError类初始化定义了reason参数,意味着当使用URLError类的对象时,可以查看错误的reason。
2. HTTPErro类

def __init__(self, url, code, msg, hdrs, fp):
    self.code = code
    self.msg = msg
    self.hdrs = hdrs
    self.fp = fp
    self.filename = url
HTTPError是URLError的子类,当HTTP发生错误将举出HTTPError。
HTTPError也是HTTP有效回应的实例,因为HTTP协议错误是有效的回应,包括状态码,headers和body。所以看到在HTTPError初始化的时候定义了这些有效回应的参数。
当使用HTTPError类的对象时,可以查看状态码,headers等
案例1:
import urllib.request
import urllib.error
try:
    headers = {'User_Agent': 'Mozilla/5.0 (X11; Ubuntu; 
                Linux x86_64; rv:57.0) Gecko/20100101 
                Firefox/57.0'}
    response = urllib.request.Request('http://python.org/', 
                                       headers=headers)
    html = urllib.request.urlopen(response)
    result = html.read().decode('utf-8')
except urllib.error.URLError as e:
    if hasattr(e, 'reason'):
        print('错误原因是' + str(e.reason))
except urllib.error.HTTPError as e:
    if hasattr(e, 'code'):
        print('错误状态码是' + str(e.code))
else:
    print('请求成功通过。')

项目实战:

import requests  # 发送请求
from lxml import etree  # 数据解析
import time  # 线程暂停,怕封ip
import os  # 创建文件夹

# 由于目标网站更新了反爬虫机制,简单的UA伪装不能满足我们的需求,所有对整个消息头进行了伪装
headers = {
    'Accept':
        'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Encoding':
        'gzip, deflate, br',
    'Accept-Language':
        'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Cache-Control':
        'max-age=0',
    'Connection':
        'keep-alive',
    'Cookie':
        '__gads=undefined; Hm_lvt_aecc9715b0f5d5f7f34fba48a3c511d6=1614145919,1614755756; '
        'UM_distinctid=177d2981b251cd-05097031e2a0a08-4c3f217f-144000-177d2981b2669b; '
        'sctj_uid=ccf8a73d-036c-78e4-6b1d-6035e961b0d3; '
        'CNZZDATA300636=cnzz_eid%3D1737029801-1614143206-%26ntime%3D1614759211; '
        'Hm_lvt_398913ed58c9e7dfe9695953fb7b6799=1614145927,1614755489,1614755737; '
        '__gads=ID=af6dc030f3c0029f-226abe1136c600e4:T=1614760491:RT=1614760491:S=ALNI_MZAA0rXz7uNmNn6qnuj5BPP7heStw; '
        'ASP.NET_SessionId=3qd454mfnwsqufegavxl5lbm; Hm_lpvt_398913ed58c9e7dfe9695953fb7b6799=1614760490; '
        'bbsmax_user=ce24ea68-9f80-42e3-8d4f-53b13b13c719; avatarId=a034b11b-abc9-4bfd-a8b2-bdf7fef644bc-; '
        'Hm_lpvt_aecc9715b0f5d5f7f34fba48a3c511d6=1614756087',
    'Host':
        'sc.chinaz.com',
    'If-None-Match':
        '',
    'Referer':
        'https://sc.chinaz.com/jianli/free.html',
    'Upgrade-Insecure-Requests':
        '1',
    'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0',
}

# 如果该文件夹不存在,则创建文件夹
if not os.path.exists('E:moban'):
    os.mkdir('E:moban')

for i in range(2, 701):  # 预计可爬700*20套简历模板
    print(f"正准备爬取第{i}页简历模板")
    print("怕封ip,操作暂停中......")  # 操作暂停提示语
    time.sleep(15)  # 每获取一个列表页暂停15s,一个列表页有20分简历模板的链接
    url = f'https://sc.chinaz.com/jianli/free_{str(i)}.html'  # 设置相应的路由i
    try:  # 异常处理
        response = requests.get(url=url, headers=headers)  # 获取响应
    except Exception as e:  # 给异常取名为e
        print(e)  # 打印异常名称
        print('连接失败,选择跳过!!!')  # 连不上就不要连了,头铁容易出事
        print("怕封ip,获取列表页操作暂停中......")  # 操作暂停提示语
        time.sleep(5)  # 每出现一次异常暂停5s
        continue  # 跳过本次循环
    response.encoding = 'utf-8'  # 中文编码为utf-8
    page = response.text  # 获取响应的文本数据
    tree = etree.HTML(page)  # 用etree进行数据解析
    a_list = tree.xpath("//div[@class='box col3 ws_block']/a")  # 用xpath提取目标内容形成20份一起的列表
 
    for a in a_list:
        resume_href = 'https:' + a.xpath('./@href')[0]  # 根据爬取的链接设置新的网页
        resume_name = a.xpath('./img/@alt')[0]  # 爬取名字,并对列表进行切片取第一个
        resume_name = resume_name.strip()  # 去掉首尾的空格
        try:
            resume_response = requests.get(url=resume_href, headers=headers)  # 进入简历模板详情页面
        except Exception as e:
            print(e)
            print('连接失败,选择跳过!!!')
            print("怕封ip,获取个人简历详情页操作暂停中......")
            time.sleep(5)
            continue
        resume_response.encoding = 'utf-8'  # 中文编码为utf-8
        resume_page = resume_response.text  # 获取响应的文本数据
        resume_tree = etree.HTML(resume_page)  # 用etree进行数据解析
        resume_link = resume_tree.xpath('//ul[@class="clearfix"]/li/a/@href')[0]  # 用xpath提取目标内容的下载链接
        try:
            download = requests.get(url=resume_link, headers=headers).content  # 获取二进制数据
        except Exception as e:
            print(e)
            print('连接失败,选择跳过!!!')
            print("怕封ip,下载个人简历操作暂停中......")
            time.sleep(5)
            continue
        download_path = 'E:moban' + resume_name + '.zip'  # 设置保存路径以及文件名称
        with open(download_path, 'wb') as fp:  # 设置文件制作,以二进制形式
            fp.write(download)  # 保存文件
            print(resume_name, '下载成功!!!')  # 下载成功提示语

 本文转载:https://segmentfault.com/a/1190000012681700






心有猛虎,细嗅蔷薇
原文地址:https://www.cnblogs.com/1314520xh/p/14769702.html