爬虫使用指南

爬虫学习

一、爬虫简介

什么是爬虫?

通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程

爬虫的价值

1.解决个性化定制的需求

2.降低成本,提高业务成功率和提高业务效率。

3.创造自己盈利价值

爬虫是合法的还是违法的?

1.爬虫在法律中是不被禁止的

2.爬虫具有违法风险

爬虫带来的风险干扰可以体现在两方面

1.爬虫干扰了被访问网站的合法运营

2.爬虫抓去了受到法律保护的特定类型的数据或信息

如何在使用爬虫的过程中进入局子?

1.时常优化自己的爬虫,避免干扰被访问网站的正常运行

2.在使用、传播爬取到的数据时,审查抓取到的内容,如果涉及到了用户隐私,或者商业机密等敏感内容,及时停止爬取或者传播


爬虫在使用场景中的分类

  • 通用爬虫:抓取系统的重要组成部分,抓取的是一整张页面数据
  • 聚焦爬虫:建立在通用爬虫的基础之上,抓取的是页面中特定的局部内容
  • 增量式爬虫:检测网站中数据更新的情况,只会抓取网站中最新更新出来的数据

爬虫的矛与盾

反爬机制

门户网站可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取

反反爬策略

爬虫程序也可以通过制定相关的策略或者奇数手段用来破解门户网站中具备的反爬机制,从而可以获取门户网站中的相关数据

robots.txt协议

君子协议,规定网站中哪些数据可以被爬虫爬取,哪些数据不可以被爬虫爬取


http协议

服务器与客户端进行数据交互的一种形式

常用请求头信息

user-agant:请求载体的身份标识

connection:请求完毕后,是断开连接还是保持连接

常用相应头信息

content-type:服务器响应回客户端的数据类型

https协议

安全的http协议(安全的超文本传输协议)

加密方式

  • 对称密钥加密
  • 非对称密钥加密
  • 证书密钥加密

二、request模块基础

requests模块

  • urllib模块
  • requests模块

requests模块

  • python中原生的一款基于网络请求的模块,功能非常强大,简单便捷,效率极高
  • 作用:模拟浏览器发请求

如何使用(requests模块的编码流程)

1.指定url
2.发起请求
3.获取响应数据
4.持久化存储

环境安装

pip install requests

实战编码

#需求:爬取搜狗首页的页面数据
import requests #导入requests模块快

#1.指定url
url = 'https://www.sogou.com/'

#2.发起请求
#get方法会返回一个响应对象
response = requests.get(url=url)

#3.获取响应数据(响应成功)
#.text返回的是字符串类型的响应数据
page_text = response.text
print(page_text)

#4.持久化存储
with open('./sougou.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

实战巩固

  • 需求:爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)

    #需求:爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)
    #UA:User-Agent(请求载体的身份标识)
    #UA检测:门户网站的服务器会检测对应的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器,意味着当前的请求是一个正常的请求
    #但是,如果检测到请求的载体身份标识不是基于某一款浏览器的,则表示该请求为爬虫,则服务器端就很有可能拒绝该次请求
    #UA伪装:让爬虫对应的请求载体身份标识伪装成某一款浏览器
    
    import requests
    
    #UA伪装:将对应的User-Agent封装到字典中
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    
    #url = 'https://www.sogou.com/web?query=%E6%B3%A2%E6%99%93%E5%BC%A0'
    #也可以写成url = 'https://www.sogou.com/web?query=波晓张'
    url = 'https://www.sogou.com/web'
    
    #处理url携带的参数:封装到字典中
    kw = input('enter a word:')
    param = {
        'query':kw
    }
    
    #对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
    response = requests.get(url=url,params=param,headers=headers)
    
    page_text = response.text
    
    #保存
    filename = './Crawler/'+ kw+'.html'
    with open(filename,'w',encoding='utf-8') as fp:
        fp.write(page_text)
    print(filename,'保存成功')
    
  • 需求:破解百度翻译

    • post请求(携带了参数)
    • 响应数据是一组json数据(需要捕获的数据)
    import requests
    import json
    
    #1.指定url
    post_url = 'https://fanyi.baidu.com/sug'
    
    #2.进行UA伪装
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    
    #3.post请求参数处理(同get请求一致)
    word = input('enter a word:')
    data = {
        'kw':word
    }
    
    #4.请求发送
    response = requests.post(url=post_url,data=data,headers=headers)
    
    #5.获取响应数据,json方法返回的是obj(对象),如果确认响应数据是json类型的,才可以使用.json()方法,进行对象返回
    dic_obj = response.json()
    
    #6.持久化存储
    filename = './Crawler/'+word+'.json'
    fp = open(filename,'w',encoding='utf-8')
    json.dump(dic_obj,fp=fp,ensure_ascii=False)
    
    print('over!')
    
  • 需求:爬取豆瓣电影分类排行榜 http://movie.douban.com/ 中的电影详情数据

    import requests
    import json
    
    url = 'https://movie.douban.com/j/chart/top_list'
    
    param = {
        'type': '24',
        'interval_id': '100:90',
        'action':'',
        'start': '0',#从数据库的第几部电影开始取 #经过校验之后发现应该是从0开始
        'limit': '20',#一次性取的个数
    }
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    
    response = requests.get(url=url,params=param,headers=headers)
    
    list_data = response.json()
    
    #持久化存储
    fp=open('./Crawler/douban.json','w',encoding='utf-8')
    
    json.dump(list_data,fp,ensure_ascii=False)
    
    print('over!')
    
  • 需求:爬取肯德基餐厅查询 http://www.kfc.com.cn/kfccda/index.aspx 中指定地点的餐厅数

  • 需求:爬取国家药品监督管理总局基于中华人民共和国化妆品生产许可证相关数据http://scxk.nmpa.gov.cn:81/xk/

  • http://scxk.nmpa.gov.cn:81/xk/itownet/portal/dzpz.jsp?id=d7b991ee5f18430eb6714321b81c14aa

    import requests
    import json
    
    #批量获取不同企业的id值
    url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    
    #存储企业id
    id_list = []
    all_data_list = []
    
    #参数的封装
    for page in range(1,6):
        page = str(page)
        data = {
            'on': 'true',
            'page': page,
            'pageSize': '15',
            'productName': '',
            'conditionType': '1',
            'applyname': '',
            'applysn':'',
        }
        #获取某一页所有企业id
        json_ids  = requests.post(url=url,headers=headers,data=data).json()
        for dic in json_ids['list']:
            id_list.append(dic['ID'])
    
    #获取企业详情数据
    post_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    
    for id in id_list:
        data = {
            'id':id
        }
        detail_json = requests.post(url=post_url,headers=headers,data=data).json()
        #print(detail_json)
        all_data_list.append(detail_json)
    
    fp = open('./Crawler/all_Data.json','w',encoding='utf-8')
    json.dump(all_data_list,fp=fp,ensure_ascii=False)
    print('over!')
    

三、数据解析

聚焦爬虫

爬取页面指定的页面内容

编码流程

  • 指定url
  • 发起请求
  • 获取响应数据
  • 数据解析
  • 进行持久化存储

数据解析分类

  • 正则
  • bs4
  • xpath(重点)

数据分析原理概述

  • 解析局部的文本内容都会在标签之间或者标签对应的属性中进行存储
    • 1.进行指定标签的定位
    • 2.标签或者标签对应的属性中存储的数据值进行提取(解析)

正则解析:

<div class="thumb">
<a href="/article/123993435" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12399/123993435/medium/U78PXLW0PH8R6ZQG.jpg" alt="糗事#123993435" class="illustration" width="100%" height="auto">
</a>
</div>

ex = '<div class="thumb">.*?<img src="(.*?)"alt.*?</div>'

需求:爬取糗事百科中糗图板块下所有的糗事图片

#需求:爬取糗事百科中糗图板块下所有的糗事图片
import requests
import re
import os

#创建一个文件夹,来保存所有的图片
if not os.path.exists('./Crawler/qiutuLibs/'):
    os.mkdir('./Crawler/qiutuLibs/')

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
}

#设置一个通用的url模板
url = 'https://www.qiushibaike.com/imgrank/page/%d/'
# page_num = 1

for page_num in range(1,13):
    #对应页码的url
    new_url = format(url%page_num)

    #使用通用爬虫对url对应的一整张页面进行爬取
    page_text = requests.get(url=new_url,headers=headers).text

    #需要使用聚焦爬虫将页面中所有的糗图进行解析
    ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
    img_src = re.findall(ex,page_text,re.S)

    #存储图片
    for src in img_src:
        #拼接出一个完整的图片url
        src = 'https:' + src
        #请求图片的二进制数据
        img_data = requests.get(url=src,headers=headers).content
        #生成图片名称,从原始图片的图片地址之中切分
        img_name = src.split('/')[-1]
        img_path = './Crawler/qiutuLibs/'+img_name
        with open(img_path,'wb') as fp:
            fp.write(img_data)
            print(img_name,'下载成功!')

bs4进行数据解析

  • 数据解析的原理

    • 标签定位
    • 提取标签、标签属性中存储的数据值
  • bs4实现数据解析的原理

    • 实例化BeautifulSoup对象,并且将页面源码的数据加载到该对象中
    • 通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
  • 环境安装

    • pip install bs4
    • pip install lxml
  • 如何实例化BeautifulSoup对象

    • from bs4 import BeautifulSoup

    • 对象的实例化

      • 1.将本地的html文档中的数据加载到该对象中

        fp = open('./test.html','r',encoding='utf-8')
        soup = BeautifulSoup(fp,'lxml')
        
      • 2.将互联网上获取的页面源码加载到该对象中

        page_text = response.text
        soup = BeautifulSoup(page_text,'lxml')
        
    • 提供用于数据解析的方法和属性

      • soup.tagName #返回的是文档中第一次出现tagName对应的标签
        
      • soup.find()

        • find('tagname') #等同于soup.div
          
        • #属性定位
          soup.find('div',class_/id/attr='xx')
          
      • soup.find_all('tagname') #返回符合要求的所有标签(列表)
        
      • select

        • select('某种选择器(id,class,标签...选择器)'),返回的是一个列表

        • 层级选择器

          • soup.select('.tang>ul>li>a') # > 表示的是一个层级
            
          • soup.select('.tang>ul>li a') #空格表示的是多个层级
            
      • 获取标签之间的文本数据

        • soup.a.text/string/get_text()
          #text,get_text():可以获得一个标签中所有的文本内容
          #string只可以获得该标签下直系文本内容
          
      • 获取标签中属性值

        • soup.a['href']
          
  • 案例:

    #需求:爬取三国演义小说所有的章节标题和章节内容
    from bs4 import BeautifulSoup
    import requests
    import os
    
    # if not os.path.exists('./Crawler/Sanguo/'):
    #     os.mkdir('./Crawler/Sanguo/')
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    #对首页的页面数据进行获取
    url='https://www.shicimingju.com/book/sanguoyanyi.html'
    page_text = requests.get(url=url,headers=headers).text
    
    #在首页中解析出章节的标题和详情页的url
    #1.实例化beautifulsoup对象,需要对页面源码数据加载到该对象中
    soup = BeautifulSoup(page_text,'lxml')
    #2.解析章节标题和详情页的url
    li_list = soup.select('.book-mulu > ul > li')
    
    fp = open('./Crawler/Sanguo.txt','w',encoding='utf-8')
    
    for li in li_list:
        print('?')
        title = li.a.string
        detial_url = 'https://www.shicimingju.com' + li.a['href']
        #3.对详情页发起请求,解析出章节内容
        detail_page_text = requests.get(url=detial_url,headers=headers).text
        #4.解析出详情页中相关的章节内容
        detail_soup = BeautifulSoup(detail_page_text,'lxml')
        div_tag = detail_soup.find('div',class_='chapter_content')
        #5.解析到了章节的内容
        content = div_tag.text
        #存储
        fp.write(title+'\n'+content+'\n')
        print(title,'爬取成功')
    

持续更新中

posted @ 2021-01-15 00:02  Dapeus  阅读(317)  评论(0)    收藏  举报