zoukankan      html  css  js  c++  java
  • 31.爬虫一

    request模块:

    - request模块的基本使用
        - python中封装好的一个基于网络亲求的模块
    - requests模块的作用
        - 用来模拟浏览器发送请求
    - requests的环境安装
        - pip install request
    - request模块的编码流程:
        - 1指定url
        - 2发起请求
        - 3获取相应数据
        - 4持久化存储
    
    # 爬取搜狗首页页面的源码数据
    import requests
    # 1.指定url
    url = 'https://www.sogou.com'
    # 2.发起请求
    response = requests.get(url=url)
    # 3.获取响应对象
    page_text = response.text
    # page_text
    # with open('sogou.html', "w", encoding='utf-8') as f:
    #     f.write(page_text)
    
    # 实现一个建议的网页采集器
    # 需要让url携带的参数动态化
    url = 'https://www.sogou.com/web/'
    # 实现参数动态化
    wd = input("enter a key:")
    params = {
        "query": wd,
    }
    # 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
    page_txt = requests.get(url,params=params).text
    
    page_txt
    

    文件乱码:

    - 上面带请求数据出现错误
        - 文件乱码
        - 没有拿到数据
        
    # 实现一个建议的网页采集器
    # 需要让url携带的参数动态化
    url = 'https://www.sogou.com/web/'
    # 实现参数动态化
    wd = input("enter a key:")
    params = {
        "query": wd,
    }
    # 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
    response = requests.get(url,params=params)
    response.encoding = 'utf-8'
    page_txt=response.text
    # page_txt 
    

    反爬机制:

    - UA检测:检测到request发送的请求载体的身份表示不是浏览器
    - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36
    
    # 结局UA检测
    # 实现一个建议的网页采集器
    # 需要让url携带的参数动态化
    import requests
    url = 'https://www.sogou.com/web'
    # 实现参数动态化
    wd = input("enter a key:")
    params = {
        "query": wd,
    }
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
    }
    # 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
    response = requests.get(url=url,params=params,headers=headers)
    response.encoding = 'utf-8'
    page_txt=response.text
    # page_txt
    

    动态加载数据爬取

    # 爬取的是豆瓣电影的详情数据
    # 当滚轮话单下面的时候动态加载数据
    # 动态加载的数据
        # 通过另一单独请求拿到的
    # url = "https://movie.douban.com/explore#!type=movie&tag=%E7%88%B1%E6%83%85&sort=recommend&page_limit=20&page_start=0"
    import requests
    # url = "https://movie.douban.com/j/chart/top_list"
    url = "https://movie.douban.com/j/search_subjects"
    
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
    }
    start = input("请输入开始页:")
    end = input("请输入结束页:")
    # dic = {
    #     "type": "13",
    #     "interval_id": "100:90",
    #     "action": "",
    #     "start": start,
    #     "limit": end,
    # }
    dic = {
        "type":"movie",
        "tag":"爱情",
        "sort":"recommend",
        "page_limit":start,
        "page_start":end,
    }
    response = requests.get(url=url,params=dic,headers=headers)
    data = response.json() # 返回json格式的数据对象
    data
    # for item in data["subjects"]:
    #     print(item["title"] + item["rate"] + str(len(data["subjects"])))
    
    # 肯德基餐厅查询数据获取
    import requests
    url = "http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
    }
    data = {
        "cname": "",
        "pid": "",
        "keyword": "北京",
        "pageIndex":"1",
        "pageSize": "10",
    }
    response = requests.post(url=url,headers=headers,data=data)
    data = response.json()
    # data
    
    - 需求分析
        - 爬取药监总局中相关企业的详情信息
    - 如何检测页面中是否存在动态加载的数据?
        - 基于抓包工具
            - 先捕获网站请求后的所有的数据包
            - 在数据包中定位到地址栏所对应请求的数据包,在response选项卡对应的数据中进行局部搜索(页面中的某一组内容)
              - 可以搜索到:爬取道的不是动态加载的
              - 搜索不到:爬取到的数据是动态加载的
        - 如何进行动态加载数据在那个数据包中?
            - 进行全局搜索
    # 页面数据接口获取
    - 需求
        - 爬取药监局总局中相关企业的http://125.35.6.84:81/zk/
    - 需求分析
        - 指定页面中企业相关数据是否为动态加载?
            - 相关企业信息是动态加载出来的
        - 通过抓包工具全局搜索,定位动态数据加载。
            - post:http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList
            - 请求返回的响应数据是一组json串,通过对json串的简单解析,没有找到企业详情页的url,但是找到每一个加企业的id
        - 每一家企业详情页的url,域名都是一样的,只有请求参数id值不同
            - 可以使用同一个域名结合这不同的id值拼接成一家完整企业详情页url
            - 判断企业详情页中的数据是否为动态加载?
                - 通过抓包工具检测,发现企业详情信息在详情页中为动态加载
                - 通过抓包工具进行全局搜索,找到数据对应的url
                    - url:post:http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById
                        - 请求参数:id: b4437b636b5944eb9eadc1418f312b19
                    - 请求到的json串就是我们最终想要的企业详细数据
    
    import requests
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
    }
    url = "http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList"
    data1 = {
        "on": "true",
        "page": "1",
        "pageSize": "15",
        "productName":"",
        "conditionType": "1",
        "applyname":"",
        "applysn":"",
    }
    
    response = requests.post(url=url,headers=headers,data=data1)
    data = response.json()
    for item in data["list"]:
        
        url2 = "http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById"
        data2 = {
            "id": item["ID"]
        }
        response2 = requests.post(url=url2, headers=headers,data=data2).json()
    #     print(response2["businessPerson"]+ response2["legalPerson"])
    

    回顾:

    - requests作用:模拟浏览器发起请求
    - urllib被requests替代了
    - request模块的编码流程:
        - 指定url
        - 发起请求
            - get(url,params,headers)
            - post(url, headers, data)
        - 获取响应数据
        - 持久化存储
    - 参数动态化
        - 有些情况下我们是需要将请求参数进行更改,将get或者post请求对应的请求参数封装到一个字典(键值对)中,然后将字典作用到get方法的params参数中或者作用到post发放的data参数中
    - UA检测(反爬机制)
        - 什么是UA:请求载体的身份表示,服务器端会检测请求的UA来鉴定身份
        - 反爬机制:UA伪装,通过抓包工具捕获某一浏览器的UA值,封装到字典中,且将该字典作用到headers参数中
    - 动态加载数据
        - 通过另一个单独的请求到的数据
    - 如果我们要对一个陌生的网站进行指定数据的爬取?
        - 首先要确定爬取的数据在该网站中是否为动态加载的
            - 是:通过抓包工具实现全局搜索,定位动态家在数据对应的数据包,从数据包中提取请求的url和请求参数
            - 不是:通过抓包工具对请求中的所有url响应进行搜索
    

    正则,xpath,bs4:

    ### 今日内容
    - 数据解析
        - 数据解析的作用
            - 可以帮助我们实现聚焦爬虫
        - 数据解析的实现方式
            - 正则
            - bs4
            - xpath(通用)
            - pyquery
        - 数据解析的通用原理
            - 问题1:聚焦爬虫爬取的数据是存在哪里?
                - 都被存储在标签之中和相关标签的属性中
            - 1.定位标签
            - 2.取文本后者属性
    
    import requests
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",
    }
    # 如何爬取图片
    url = "https://pic.qiushibaike.com/system/pictures/12296/122968969/medium/LSG56EWMA84YO922.jpg"
    img_data = requests.get(url=url, headers=headers).content
    # with open("./img.jpg","wb") as f:
    #     f.write(img_data)
    
    # 方式二
    # 不可以使用UA伪装
    from urllib import request
    url = "https://pic.qiushibaike.com/system/pictures/12296/122968969/medium/LSG56EWMA84YO922.jpg"
    # request.urlretrieve(url,filename="./qiushi.jpg")
    

    正则解析:

    <a class="recmd-left multi" href="/article/122969075" rel="nofollow" target="_blank" onclick="_hmt.push(['_trackEvent','web-list-multi','chick'])">
    
    <img src="//qiubai-video-web.qiushibaike.com/article/gif/RP2LJ8DOWG2TVP7T.jpg?imageView2/1/w/150/h/112" alt="一直给女友吹嘘我厨艺">
    
    <div class="recmd-tag">1图</div>
    </a>
    ex = '<a class="recmd-left.*?<img src="(.*?)" alt=.*?</a>'
    
    # 正则(麻烦)
    # 糗事百科图片爬取1-3页所有的图片
    # 设置一个通用的url模板(不可变)
    import re
    import os
    if not os.path.exists("./imgLibs"):
        os.mkdir('imgLibs')
    url = "https://www.qiushibaike.com/8hr/page/%d/"
    ex = '<a class="recmd-left.*?<img src="(.*?)?.*?" alt=.*?</a>'
    for i in range(1,4):
        new_url = format(url%i)
        img_data = requests.get(url=new_url, headers=headers).text
        img_list = re.findall(ex, img_data,re.S)
        for src in img_list:
            src = "https:" + src
            img_name = src.split("/")[-1]
            img_path = "imgLibs/" + img_name
            request.urlretrieve(src, img_path)
    

    b64:

    - bs4解析
        - bs4解析的原理
            - 实例化一个Beautifulsoup的对象,需要将即将被解析的页面源码数据加载到该对象中
            - 调用BeautifulSoup对象中的想过方法和属性进行标签定位和数据提取
        - 环境安装
            - pip install bs4
            - pip install lxml
        - BeautifulSoup的实例化
            - BeautifulSoup(fp,'lxml'),将背地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中
            - BeautifulSoup(page_text, "lxml"),将从互联网上获取到的页面源码数据加载到实例化好的BeautifulSoup对象中
            
    - 定位标签的操作
        - soup.tagName:定位第一个出现的tagName标签
        - 属性定位:soup.find("tagName", attrName='value')
        - 属性定位:soup.find_all("tagName", attrName='value') # 返回列表
        - 选择器定位:soup.select('选择器') # 返回一个列表
            - 层级选择器:>表示一个层级,空格代表多个层级
    - 取文本
        - .sting:只可以获取直系的文本内容
        - .text:
    - 去属性
        - ['属性名称']
    
    from bs4 import BeautifulSoup
    fp = open("./test.html", "r", encoding="utf-8")
    soup = BeautifulSoup(fp, "lxml")
    soup.div
    soup.find("div", class_="song")
    soup.find("a", id="feng" )
    soup.find_all("div", class_="song")
    
    soup.select('.song')
    soup.select('.tang > ul > li')
    soup.select('.tang li')
    
    a_tag = soup.select('#feng')[0]
    a_tag.text
    
    div = soup.div
    div.string
    
    div = soup.find('div',class_='song')
    div.string
    
    a_tag = soup.select('#feng')[0]
    a_tag["href"]
    
    # 爬取三国整片内容 
    from bs4 import BeautifulSoup
    fp = open("./sanguo.txt",'w',encoding="utf-8")
    page_url = "http://www.shicimingju.com/book/sanguoyanyi.html"
    page_text = requests.get(url=page_url, headers=headers).text
    soup = BeautifulSoup(page_text, "lxml")
    a_list = soup.select('.book-mulu > ul > li > a') # 返回的列表中存储的是一个个li标签
    for a in a_list:
        title = a.string
        detail_url = "http://www.shicimingju.com" + a['href']
        detail_page_text = requests.get(url=detail_url, headers=headers).text
        # 解析详情页中的章节内容
        soup1 = BeautifulSoup(detail_page_text, "lxml")
        content = soup1.find('div', class_='chapter_content').text
    #     fp.write(title + ":" + content + "
    ")
    #     print(title, "下载成功")
    # # print("over")
    

    xpath:

    - xpath解析
        - xpath解析实现的原理
            - 1.实例化一个etree对象,然后将即将被解析的页面源码加载到该对象中
            - 2.使用etree对象中xpath方法结合这不同形式的xpath表达式实现标签定位和数据提取
        - 环境安装
            pip install lxml
        - etree对象实例化
            - etree.parse('test.html')
            - etree.HTML(page_text)
            
    - xpath表达式
        - 最左侧的/表示:xpath表达式一定要从跟标签逐层进行查找和定位
        - 最左侧//表示:xpath表达式可以从任意位置定位标签
        - 非最左侧的/:表示一个层级
        - 非最左侧//表示:表示多个层级
        - 属性定位://tagName[@attrName="value"]
        - 索引定位:
    - 取文本:
        - /text() : 直系文本
        - //text() : 所有的文本内容
    - 取属性
        - /@attrName
    
    from lxml import etree
    tree = etree.parse('./test.html')
    tree.xpath('/html/head/title')
    tree.xpath('//title')
    tree.xpath('//dic[@class="song"]')
    tree.xpath('//li[2]/text()')
    tree.xpath("//li[2]/a/@href")
    
    # 爬取糗事百科段子内的作者名称
    import requests
    from lxml import etree
    url = "https://www.qiushibaike.com/text/"
    page_text = requests.get(url=url, headers=headers).text
    # 解析内容
    tree = etree.HTML(page_text)
    div_list = tree.xpath("//div[@class='col1 old-style-col1']/div")
    for div in div_list:
        author = div.xpath('./div[1]/a[2]/h2/text()')[0]
        content = div.xpath('./a[1]/div/span/text()')
        content = "".join(content)
    #     print(author,content)
    

    合并条件:

    # 合并xpath表达式,提高xpath的通用性
    a.xpath("./b/text() | ./img/@src")
    

    错误分析

    - HttpConnectionPoll
        - 原因:
            - 短时间内发起了太多请求
            - http连接池中的连接资源被耗尽
        - 解决:
            - 使用代理
            - headers中加入Conection:"close"
    
  • 相关阅读:
    从 MVC 到微服务,技术演变的必经之路
    JBOSS最大连接数配置和jvm内存配置
    数据库原理及应用第7章课后习题答案
    如何实现超高并发的无锁缓存?
    手工清理win7系统C盘的技巧
    SVN版本回退
    在sql server数据库的一个表中如何查询共有多少字段
    软件测试的四个阶段
    sp_change_users_login 'Update_One', '用户名', '登录名';
    讲一讲java异常及自定义异常
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/12674610.html
Copyright © 2011-2022 走看看