1-爬虫-爬虫介绍、爬虫初识、图片数据爬取

爬虫介绍

  • Anaconda

    • python中基于数据分析+机器学习的一个集成环境

  • jupyter

    • Anaconda提供的一款基于浏览器的可视化编码工具

  • 什么爬虫

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

  • 爬虫的分类

    • 通用爬虫:抓取一整张页面源码数据

    • 聚焦爬虫:抓取一整张页面中的局部内容

      • 聚焦爬虫是需要建立在通用爬虫基础之上

    • 增量式爬虫

    • 分布式爬虫

  • 反爬机制:

    • 是需要应用在网站中。反爬机制的指定来阻止爬虫程序对其网站数据的爬取

  • 反反爬策略

    • 是需要应用在爬虫中。指定相关的反反爬策略来破解网站的反爬机制从而爬取网站中相关的数据。

  • requests模块

    • 概念:一个基于网络请求的模块,该模块可以模拟浏览器上网。

    • 环境安装:pip install requests

    • 编码流程:

      • 1.指定url

      • 2.发起请求

      • 3.获取响应数据

      • 4.持久化存储

爬虫初识

#爬取一下搜狗首页的页面源码数据
import requests
#1.
url = 'https://www.sogou.com/'
#2.get方法会返回一个响应对象
response = requests.get(url=url) #根据指定的url发起get请求
#3.
page_text = response.text #获取了字符串形式的响应数据
print(page_text)
#4.
with open('./sogou.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
  • 实现一个简易的网页采集器

    • 基于搜狗实现对任意关键字页面数据的爬取

url = 'https://www.sogou.com/web?query=jay'
response = requests.get(url=url)
page_text = response.text
with open('./jay.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
  • 上述代码出现了问题:

    • 问题1:乱码的出现

    • 问题2:数据量级少

#乱码的处理
url = 'https://www.sogou.com/web?query=jay'
response = requests.get(url=url)
#设置响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
with open('./jay.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
  • 什么是异常访问请求?

    • 只要不是浏览器发起的请求就是异常的访问请求。

  • 网站后台是如何检测请求是否为异常的请求?

    • 通过对请求头中的User-Agent进行检测即可

  • 什么是User-Agent:

    • 请求头中的信息。UA表示的请求载体的身份标识。

  • 第一个反爬机制:UA检测

    • 网站后台会检测请求的UA值,如果请求的载体为爬虫,则阻止提供数据

  • 反反爬策略:UA伪装

    • 将爬虫发起请求的UA伪装成某一款浏览器即可

url = 'https://www.sogou.com/web?query=jay'
#进行UA伪装
headers = {#封装请求头
    'User-Agent':'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'
}
#携带请求头进行请求发送
response = requests.get(url=url,headers=headers)
#设置响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
with open('./jay.html','w',encoding='utf-8') as fp:
    fp.write(page_text)
  • 参数的动态化

    • 可以动态的指定请求参数

kw = input('enter a key word:')
params = {#封装请求参数
    'query':kw
}
url = 'https://www.sogou.com/web'
#进行UA伪装
headers = {#封装请求头
    'User-Agent':'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'
}
#携带请求头进行请求发送
response = requests.get(url=url,headers=headers,params=params)
#设置响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
fileName = kw+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
    fp.write(page_text)
  • 动态加载数据的爬取

    • 豆瓣电影,当滚轮滑动到底部,发生了回弹并且页面中加载出了更多的电影数据。

    • 这个现象说明当滚轮滑动底部时,发起了一个ajax请求,请求到了更多的电影数据

    • 概念:通过另一个新的请求请求到的数据叫做动态加载数据。动态加载的数据是无法通过对浏览器地址栏的url发请求获取的。

  • 如何检测我们想要的数据是否为动态加载数据

    • 基于抓包工具做局部搜索

  • 如何捕获动态加载数据

    • 基于抓包工具做全局搜索。定位到动态加载数据对应的数据包,从数据包中可以提取出请求的url,请求方式,请求参数

url = 'https://movie.douban.com/j/chart/top_list'
params = {
    'type': '11',
    'interval_id': '100:90',
    'action': '',
    'start': '0',
    'limit': '100',
}
response = requests.get(url=url,params=params,headers=headers)
json_data = response.json() #json()可以将字符串序列化成对象
for dic in json_data:
    name = dic['title']
    score = dic['score']
    print(name,score)
  • 爬取肯德基的餐位位置信息

  • 分析:当点击了查询按钮后,位置信息才动态刷新出来,且通过抓包工具进行局部搜索,没有搜到结果说明数据为动态加载数据

  • 通过基于抓包工具进行全局搜索

url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
for i in  range(1,5):
    data = {
        'cname':'' ,
        'pid': '',
        'keyword': '上海',
        'pageIndex': str(i),
        'pageSize': '10',
    }
    response = requests.post(url=url,headers=headers,data=data)
    data = response.json()['Table1']
    for dic in data:
        name = dic['storeName']
        address = dic['addressDetail']
        print(name,address)
  • 如果在爬取一个新网站数据时,操作的第一部一定是先检测想要爬取的数据是否为动态加载。

  • 动态加载的数据生成方式:

    • ajax请求生成

    • js

  • 需求:

  • 分析:

    • 1.某一家企业数据的爬取流程

    • 2.一家企业的数据是否为动态加载

      • 为动态加载

    • 3.抓包工具进行全局搜索

    • 4.发现不同企业对应数据的url和请求方式一样,只有请求参数id的值不同

    • 5.每一家企业的id如何获取

      • 可能性:企业id和企业名称可能是关联在一起

main_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
for page in range(1,6):
    data = {
        'on': 'true',
        'page': str(page),
        'pageSize': '15',
        'productName': '',
        'conditionType': '1',
        'applyname': '',
        'applysn': '',
    }
    data = requests.post(url=main_url,headers=headers,data=data).json()['list']
    for dic in data:
        id_ = dic['ID']
        url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
        data = {
            "id": id_
        }
        detail_data = requests.post(url=url,headers=headers,data=data).json()
        print(detail_data)

图片数据爬取

import requests
headers = {
    'User-Agent':'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:
url = 'https://pic.qiushibaike.com/system/pictures/12329/123293159/medium/2UOCOGU7XI5AOK9C.jpg'
response = requests.get(url=url,headers=headers)
#图片,视频,音频都是以二进制数据存在(bytes)
img_data = response.content #返回的是bytes类型的响应数据
with open('./123.png','wb') as fp:
    fp.write(img_data)
#方式2:基于urllib实现
import urllib #urllib就是一个低级requests
url = 'https://pic.qiushibaike.com/system/pictures/12329/123293159/medium/2UOCOGU7XI5AOK9C.jpg'
urllib.request.urlretrieve(url=url,filename='./456.jpg')
  • 方式1和方式2的主要不同之处:

    • 方法1可以实现UA伪装,方式2不可

  • 需求:批量爬取糗事百科中的所有的图片数据

  • 数据解析:可以将页面中指定的局部数据进行提取

    • bs4

    • xpath

    • pyquery

  • 浏览器开发者工具中的Elemente和netword选项卡的区别:

    • 如果浏览器地址栏对应页面中没有动态加载的数据,则这两者显示的页面源码无区别

    • 如果存在动态加载数据,则Element中显示的页面源码数据表示所有请求加载数据完毕后对应的总数据,而network中仅仅显示地址栏url这一个请求对应的数据。

#通过正则提取出每一张图片的图片地址
import re,os
​
dirName = './libs'
if not os.path.exists(dirName):
    os.mkdir(dirName)
    
url = 'https://www.qiushibaike.com/imgrank/'
page_text = requests.get(url=url,headers=headers).text
ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
#一定要注意回车问题:re.S可以让正则表达式忽略回车
img_src_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
    src = 'https:'+src
    img_name = src.split('/')[-1]
    img_path = dirName+'/'+img_name
    
    img_data = requests.get(url=src,headers=headers).content
    with open(img_path,'wb') as fp:
        fp.write(img_data)
    print(img_name,'爬取成功!!!')
  • 通过分析不同页码的链接发现,不同页码的链接不同之处仅在于链接的页码不同:

#将所有页码的图片数据进行爬取
dirName = './libs'
if not os.path.exists(dirName):
    os.mkdir(dirName)
    
url_model = 'https://www.qiushibaike.com/imgrank/page/%d/'#不可变
for page in range(1,14):
    print('正在爬取第%d页的图片数据......'%page)
    new_url = format(url_model%page)
    page_text = requests.get(url=new_url,headers=headers).text
    ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
    #一定要注意回车问题:re.S可以让正则表达式忽略回车
    img_src_list = re.findall(ex,page_text,re.S)
    for src in img_src_list:
        src = 'https:'+src
        img_name = src.split('/')[-1]
        img_path = dirName+'/'+img_name
​
        img_data = requests.get(url=src,headers=headers).content
        with open(img_path,'wb') as fp:
            fp.write(img_data)
        print(img_name,'爬取成功!!!'
  • 数据解析后序

  • requests高级

  • robots.txt协议(君子协议)

    • 指定了网站中可爬和不可爬的目录

    • 没有采用强硬的相关机制阻止爬虫的爬取

作业

任务:

原文地址:https://www.cnblogs.com/wgwg/p/13227356.html