python爬虫

爬虫心得

爬虫的最终目的是通过程序模拟用户上网,爬取目标网站的相关数据。那么,就需要有python数据结构的相关知识,主要涉及序列、元组和字典。

  • 序列

    序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。

    list1 = ['physics', 'chemistry', 1997, 2000]
    
  • 元组

    tup1 = ('physics', 'chemistry', 1997, 2000)
    
  • 字典

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    
    #访问字典里的值
    dict['Name']
    #输出字典可打印的字符串表示	
    str(dict)
    

GET请求目标网站

  • 实现步骤:

    第一步:获取目标网站的url

    第二步:通过requests库发送get请求

    第三步:设置参数用来接收返回的网站

    第四步:通过xpath解析数据

  • 案例分析

    import requests
    from lxml import etree
    
    url="http://www.sxjybk.com/gdjy.htm"
    headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
    }
    resp=requests.get(url,headers=headers);
    resp.encoding=resp.apparent_encoding
    html=etree.HTML(resp.text);
    
    #获取总页数
    _pageNum=html.xpath("/html/body/div[3]/div[3]/div/span/span[9]/a/text()")
    pageNum="".join(_pageNum);#数组转字符串
    #print(pageNum)
    currentPage=int(pageNum)
    while currentPage>0:
        page_url = "http://www.sxjybk.com/gdjy/"+str(currentPage)+".htm"
        #print(page_url)
        #currentPage=currentPage-1
        _resp = requests.get(page_url, headers=headers);
        _resp.encoding = _resp.apparent_encoding
        html = etree.HTML(_resp.text);
        a_list=" ".join(html.xpath("/html/body/div[3]/div[3]/ul/li/a[2]/@href"))
        #print(a_list)
        news_list=a_list.replace("..","http://www.sxjybk.com/").split()
        #print(news_list)
        for href in news_list:
            #print(href)
            resp = requests.get(href, headers=headers);
            resp.encoding = resp.apparent_encoding
            item_html = etree.HTML(resp.text)
            #print(item_html)
            content = "".join(item_html.xpath("//html/body/div[3]/form/div[3]/div[1]/div/p/text()"))
            title = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/span[2]/text()"))
            source = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/div[1]/span[1]/text()")).strip().replace("来源:"," ")
            date_time = "".join(item_html.xpath("/html/body/div[3]/form/div[1]/div[1]/span[3]/text()")).replace('年', '-').replace('月', '-').replace('日', '')
            #print(date_time)
            if content!="":
                edu_info = {
                    "title": title,
                    "date": date_time,
                    "source": source,
                    "content": content
                }
            else:
                content_02="".join(item_html.xpath("/html/body/div[3]/form/div[3]/div[1]/div/div/p/text()"))
                edu_info = {
                    "title": title,
                    "date": date_time,
                    "source": source,
                    "content": content_02
                }
            print(edu_info)
        currentPage=currentPage-1
        #print(page_url)
    resp.close();
    

POST请求目标网站

如果通过xpath解析,返回的是空列表,然后通过谷歌浏览器开发者模式,在response的源代码中搜索目标内容,如果没搜到,并且再次发送请求网站没刷新,很大程度上,该页面是通过ajax发出异步请求将返回的数据渲染在页面上的。

  • 实现步骤

    第一步:获取目标网站的url

    第二步:通过requests库发送get请求

    第三步:设置参数用来接收返回的网站

    第四步:通过xpath解析数据

  • 案例分析:

    import requests
    from lxml import etree
    import re
    
    url = "https://www.shxbe.com/front/node/4/nodeData"
    params = {
        'nodeId': 4,
        'pageSize': 9,
        'curPage': 1
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
    }
    resp = requests.post(url, headers=headers, data=params);
    resp.encoding = resp.apparent_encoding
    html = etree.HTML(resp.text);
    if resp.status_code == 200:
        info = resp.json()  # 解析内容为json返回
        current_page = int(info["curPage"])
        pageNum = int(info['totalPage'])
    while current_page <= pageNum:
        page_url = "https://www.shxbe.com/front/node/4/nodeData"
        params = {
            'nodeId': 4,
            'pageSize': 9,
            'curPage': current_page
        }
        _resp = requests.post(page_url, headers=headers, data=params);
        _resp.encoding = _resp.apparent_encoding
        html = etree.HTML(_resp.text);
        if _resp.status_code == 200:
            info = _resp.json()  # 解析内容为json返回
            id_list = info["list"]
            for value in id_list:
                href = "https://www.shxbe.com/front/node/recordInfor/" + str(value['id'])
                resp = requests.get(href, headers=headers);
                resp.encoding = resp.apparent_encoding
                item_html = etree.HTML(resp.text)
                title = "".join(item_html.xpath("/html/body/div[2]/div[2]/h1/text()"))
                source = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[3]/p/i[1]/text()"))
                date = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[1]/div[1]/i/text()"))
                _content = "".join(item_html.xpath("/html/body/div[2]/div[2]/div[2]/p/span/text()"))
                content = re.sub("\s", '', _content);
                if content != "":
                    edu_info = {
                        'title': title,
                        'source': source,
                        'date': date,
                        'content': content
                    }
                    print(edu_info)
        current_page = current_page + 1
    resp.close()
    

几个重要的方法

  • 字符串相关

    方法说明
    “”.join(param1)将param1转字符串
    str(obj)返回一个对象的string格式
    strip()去除首尾空格
  • re相关

    • 正则表达式

      量词 控制前面的元字符出现的次数

      量词说明
      *重复零次或多次
      +重复1次或多次
      重复0次或一次
      {n}重复n次
      .*贪婪匹配
      .*?惰性匹配

      常用元字符

      模式描述
      ^匹配字符串的开头
      $匹配字符串的末尾。
      .匹配换行符以外的任意字符
      […]用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’
      [^…]不在[]中的字符
      \w匹配字母、数字、下划线
      \s匹配任意空白字符,等价于 [ \t\n\r\f]
      \d匹配任意数字,等价于 [0-9]
    • 方法

      引入re库:import re

      方法名说明举例
      sub(pattern, repl, string, count=0, flags=0)替换字符串中的匹配项content = re.sub("\s", ‘’, _content);替换空白字符
      findall(string[, pos[, endpos]])返回正则表达式所匹配的所有子串 列表source = re.findall(r"文章来源:(.+?) ", _source)

tips

一、伪装成正常访问 审查元素 Networks--Headers---User-Agent
    headers={User-Agent:"  "}
    requests.get(url,headers=headers)
    
二、爬取最后一步   resp.close()

三、数据解析
(1)re解析 正则表达式  re模块
(2)bs4解析
(3)xpath解析
    安装lxml   pip install lxml
    匹配规则:
        /表示层级关系,第一个/是根节点
        text()取标签内容
        //后代
        *任意的节点,通配符
    页面复杂时,结合浏览器审查元素  copy xpath路径
    
四、请求参数过长,重新封装参数
Network-->Headers-->Query String Parameters (保存在params)
url="https://Www.baidu.com"
params={
  "name":"pinkhub"
}
等价于url="https://www.baidu.com/?name=pinkhub"

安装requests插件  pip install requests
                  换源加速 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
五、注意点
1.如果xpath路径中存在tbody,要删掉tbody
2.发出请求没返回内容
(1)UA伪装
(2)反爬机制
3.乱码问题  windows系统电脑默认是gbk,需添加encoding='utf-8'
4.robots.txt协议 规范爬虫  网址/robots.txt
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值