day02

回顾

  • 爬虫

  • 爬虫的分类:

    • 通用

    • 聚焦

    • 增量式:监测

  • 反爬机制

  • 反反爬策略

  • robots,UA监测:UA伪装

  • http&https概念:服务器和客户端进行数据交互的某种形式

  • 常用的头信息:

    • User-Agent:请求载体的身份标识

    • Connection:close

    • content-type

  • https的加密方式:证书秘钥加密

    • 证书:是被应用在https的加密操作中的.该证书是有证书认证机构颁布的,证书中包含了公钥(加密方式)

  • requests:

    • get/post:

      • url

      • data/params:对请求参数的封装

      • headers:UA伪装

    • 什么是动态加载的数据:由另一个额外的请求请求到的数据

      • ajax

      • js

    • 如何鉴定页面中是否有动态加载的数据?

      • 局部搜索

      • 全局搜索

    • 对一个陌生网站进行爬取前的第一步做什么?

      • 确定你要爬取的数据是否为动态加载的!!!

数据解析

  • 解析:根据指定的规则对数据进行提取

  • 作用:实现聚焦爬虫

  • 聚焦爬虫的编码流程:

    • 指定url

    • 发起请求

    • 获取响应数据

    • 数据解析

    • 持久化存储

  • 数据解析的方式:

    • 正则

    • bs4

    • xpath

    • pyquery(拓展)

  • 数据解析的通用原理是什么?

    • 数据解析需要作用在页面源码中(一组html标签组成的)

    • html的核心作用是什么?

      • 展示数据

    • html是如何展示数据的呢?

      • html所要展示的数据一定是被放置在html标签之中,或者是在属性中.

    • 通用原理:

      • 1.标签定位

      • 2.取文本or取属性

正则实现的数据解析

  • 需求:爬取糗事百科中糗图数据

  • 如何爬取图片数据

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

#方式1:
url = 'https://pic.qiushibaike.com/system/pictures/12217/122176396/medium/OM37E794HBL3OFFF.jpg'
img_data = requests.get(url=url,headers=headers).content #content返回的是byte类型的数据
with open('./123.jpg','wb') as fp:
    fp.write(img_data)

#方式2:
from urllib import request
url = 'https://pic.qiushibaike.com/system/pictures/12217/122176396/medium/OM37E794HBL3OFFF.jpg'
request.urlretrieve(url,'./456.jpg')

  

  • 方式1和方式2对于图片数据爬取的操作最大的不同之处是在哪?

    • 方式2不可以使用UA伪装的机制

  • urllib就是一个比较老的网络请求的模块,在requests模块没有出现之前,请求发送的操作使用的都是urllib

#糗事百科
import re
import os
​
dir_name = './qiutuLibs'
if not os.path.exists(dir_name):
    os.mkdir(dir_name)
​
url = 'https://www.qiushibaike.com/pic/'
page_text = requests.get(url,headers=headers).text
#数据解析:图片地址
ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
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 = dir_name+'/'+img_name
    #对图片地址单独发起请求获取图片数据
    request.urlretrieve(src,img_path)
    print(img_name,'下载成功!!!')

 

dir_name = './qiutuLibs'
if not os.path.exists(dir_name):
    os.mkdir(dir_name)
#指定一个通用的url模板(不可变)
url = 'https://www.qiushibaike.com/pic/page/%d/'
for page in range(1,5):
    print('正在爬取第{}页的图片'.format(page))
    #形成一个某页码完整的url
    new_url = format(url%page)
    page_text = requests.get(new_url,headers=headers).text
    #数据解析:图片地址
    ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
    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 = dir_name+'/'+img_name
        #对图片地址单独发起请求获取图片数据
        request.urlretrieve(src,img_path)
#         print(img_name,'下载成功!!!')

 

bs4解析

  • 环境的安装:

    • pip install bs4

    • pip install lxml

  • bs4的解析原理

    • 实例化一个BeautifulSoup的对象,并且将即将被解析的页面源码数据加载到该对象中

    • 调用BeautifulSoup对象中的相关属性和方法进行标签定位和数据提取

  • 如何实例化BeautifulSoup对象呢?

    • BeautifulSoup(fp,'lxml'):专门用作于解析本地存储的html文档中的数据

    • BeautifulSoup(page_text,'lxml'):专门用作于将互联网上请求到的页面源码数据进行解析

标签定位

  • soup.tagName:定位到第一个TagName标签,返回的是单数

  • 属性定位:soup.find('tagName',attrName='value'),返回也是单数

    • find_all:和find用法一致,但是返回值是列表

  • 选择器定位:select('选择器'),返回值为列表

    • 标签,类,id,层级(>:一个层级,空格:多个层级)

提取数据

  • 取文本:

    • tag.string:标签中直系的文本内容

    • tag.text:标签中所有的文本内容

  • 取属性:

    • tag['attrName']

from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml') #将即将被解析的页面源码加载到该对象中
soup.p
soup.find('div',class_='song')
soup.find_all('div',class_='song')
soup.select('.tang')
soup.select('#feng')
soup.select('.tang > ul > li')
soup.select('.tang li')
li_6 = soup.select('.tang > ul > li')[6]
i_tag = li_6.i
i_tag.string
soup.find('div',class_='tang').text
soup.find('a',id="feng")['href']
'http://www.haha.com'

 

#在首页中解析章节名称&每一个章节详情页的url
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url,headers=headers).text
soup = BeautifulSoup(page_text,'lxml')
a_list = soup.select('.book-mulu > ul > li > a')
fp = open('sanguo.txt','w',encoding='utf-8')
for a in a_list:
    detail_url = 'http://www.shicimingju.com'+a['href']
    chap_title = a.string
    #对章节详情页的url发起请求,解析详情页中的章节内容
    detail_page_text = requests.get(detail_url,headers=headers).text
    soup = BeautifulSoup(detail_page_text,'lxml')
    chap_content = soup.find('div',class_="chapter_content").text
    fp.write(chap_title+':'+chap_content+'\n')
    print(chap_title,'爬取成功!')
fp.close()

 

xpath解析

  • 环境的安装:pip install lxml

  • xpath的解析原理

    • 实例化一个etree类型的对象,且将页面源码数据加载到该对象中

    • 需要调用该对象的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取

  • etree对象的实例化

    • etree.parse(fileNane)

    • etree.HTML(page_text)

  • xpath方法返回的永远是一个列表

标签定位

  • 在xpath表达式中最最侧的/表示的含义是说,当前定位的标签必须从根节点开始进行定位

  • xpath表达式中最左侧的//表示可以从任意位置进行标签定位

  • xpath表达式中非最左侧的//表示的是多个层级的意思

  • xpath表达式中非最左侧的/表示的是一个层级的意思

  • 属性定位://tagName[@arrtName='value']

  • 索引定位://tagName/li[3]

提取数据

  • 取文本:

    • /text():取直系的文本内容

    • //text():取所有的文本内容

  • 取属性:

    • tag/@attrName

from lxml import etree
tree = etree.parse('./test.html')
tree.xpath('/html/head/meta')[0] #绝对路径
tree.xpath('//meta')[0] #相对路径,将整个页面源码中所有的meta进行定位
tree.xpath('/html//meta')[0] 
#属性定位
tree.xpath('//div[@class="song"]')
#索引定位
tree.xpath('//div[@class="tang"]/ul/li[3]') #该索引是从1开始
tree.xpath('//div[@class="tang"]//li[3]') #该索引是从1开始
#取文本
tree.xpath('//p[1]/text()')
tree.xpath('//div[@class="song"]//text()')
​
#取属性
tree.xpath('//a[@id="feng"]/@href')
['http://www.haha.com']

 

  • 需求:爬取boss的招聘信息

    • 岗位名称

    • 公司名称

    • 薪资

    • 岗位描述

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
    'cookie':""
}
url = 'https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&city=101010100&industry=&position='
page_text = requests.get(url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="job-list"]/ul/li')
for li in li_list:
#     需要将li表示的局部页面源码数据中的相关数据进行提取
#     如果xpath表达式被作用在了循环中,表达式要以./或者.//开头
    detail_url = 'https://www.zhipin.com'+li.xpath('.//div[@class="info-primary"]/h3/a/@href')[0]
    job_title = li.xpath('.//div[@class="info-primary"]/h3/a/div/text()')[0]
    salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()')[0]
    company = li.xpath('.//div[@class="info-company"]/div/h3/a/text()')[0]
    #对详情页的url发请求解析出岗位职责
    detail_page_text = requests.get(detail_url,headers=headers).text
    tree = etree.HTML(detail_page_text)
    job_desc = tree.xpath('//div[@class="text"]//text()')
    job_desc = ''.join(job_desc)
    
    print(job_title,salary,company,job_desc)

 

  • 另一种较为通用的xpath表达式的使用形式:管道符在xpath表达式中的应用,用于解析不规则布局的页面数据

  • 爬取糗事百科的段子内容和作者名称

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
}
url = 'https://www.qiushibaike.com/text/page/4/'
page_text = requests.get(url,headers=headers).text
​
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@id="content-left"]/div')
for div in div_list:
    author = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()')[0]
    content = div.xpath('.//div[@class="content"]/span//text()')
    content = ''.join(content)
    print(author,content)
    

 

中文乱码处理的问题

#指定一个通用的url模板
url = 'http://pic.netbian.com/4kmeishi/index_%d.html'for page in range(1,3):
    if page == 1:
        new_url = 'http://pic.netbian.com/4kmeishi/'
    else:
        new_url = format(url%page)
    response =  requests.get(new_url,headers=headers)
    #response.encoding = 'utf-8'
    page_text = response.text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li')
    for li in li_list:
        img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
        img_name = li.xpath('./a/b/text()')[0]
        img_name = img_name.encode('iso-8859-1').decode('gbk')
        

 


    
posted @ 2020-07-22 22:43  老宝  阅读(46)  评论(0)    收藏  举报