Python爬虫三种解析方式,Pyhton360搜索排名查询

时间:2022-07-22
本文章向大家介绍Python爬虫三种解析方式,Pyhton360搜索排名查询,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

python爬虫中有三种解析网页的方式,正则表达式,bs4以及xpath,比较受用户喜爱的是bs4以及xpath,后期使用频率较高的是xpath,因为Scrapy框架默认使用的就是xpath解析网页数据。

数据解析方式  

  - 正则

  - xpath

  - bs4

正则 数据解析的原理:

  • 标签的定位
  • 提取标签中存储的文本数据或者标签属性中存储的数据

bs4解析

  • 解析原理:
    • 实例化一个Beautifulsoup的对象,且将页面源码数据加载到该对象中
    • 使用该对象的相关属性和方法实现标签定位和数据提取
  • 环境的安装:
    • pip install bs4
    • pip install lxml
  • 实例化Beautifulsoup对象
    • BeautifulSoup(page_text,'lxml'):将从互联网上请求到的页面源码数据加载到该对象中
    • BeautifulSoup(fp,'lxml'):将本地存储的一样页面源码数据加载到该对象中
    • 属性
soup.a.attrs 返回一字典,里面是所有属性和值
soup.a['href'] 获取href属性
soup.a.string
soup.a.text
soup.a.get_text()

xpath解析:

- 解析效率比较高
- 通用性最强的

- 环境安装:pip install lxml
- 解析原理:
    - 实例化一个etree对象且将即将被解析的页面源码数据加载到该对象中
    - 使用etree对象中的xpath方法结合着xpath表达式进行标签定位和数据提取
- 实例化etree对象
    - etree.parse('本地文件路径')
    - etree.HTML(page_text)

在网页数据解析当中,re正则解析是比较费劲的,而且非常容易出错,网页数据结构一旦出错,则容易报出异常,而且想要匹配好正则,你的正则表达式需要熟练,不然你得一步步去尝试了,某些网页数据解析还真的只能用正则表达式去匹配。

如果你有接触过火车头采集器,那么对于正则,应该不会陌生!

实例的方式为大家展示Python爬虫三种解析方式

Pyhton360搜索排名查询

关于搜索排名的结果查询,前面有分享过Python百度的搜索排名查询

360搜索排名查询,大同小异,比较烦人的就是协议头的处理

#构建协议头
def ua():
    ua=UserAgent()
    headers={
        'Cookie': 'QiHooGUID=622250714BFE7FEEBC7BE97B1768B7F1.1578470720454; _S=ilmjtet5usmi3a5005tq7of442; opqopq=d8a79fec6212514efe440041e132813c.1578470720',
        'Referer': 'https://www.so.com/haosou.html',
        "User-Agent":ua.random,
    }
    return headers

第一个就是ua,还有就是cookies,最后一个就是Referer的添加,这个在图片的反爬中比较常见!

协议头不对的反馈,相信你也会碰到!

三种解析方式的处理,那就在细节上有小差异,同时还有部分数据的处理!

数据处理的关键点:

1.eval()函数

将str转为字典,提取排名

2.排名为空的情况

这里我用异常处理了

re正则的话写了 if else判断处理

3.xpath多个数据获取后的处理

title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理

join函数以及切片的处理

bs4解析

#bs4获取数据
def get_bs4search(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        soup=BeautifulSoup(req,"html.parser")
        lis=soup.find("ul",class_="result").find_all("li",class_="res-list")
        print(len(lis))
        for li in lis:
            title=li.find("a").get_text()
            site_url=li.find("a")['href']
            try:
                pos=eval(li.find("a")['data-res'])['pos']  #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg=cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg !=[]:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")

find以及find_all方法

#find方法
#find只能找到符合要求的第一个标签,他返回的是一个对象
soup.find('a')
soup.find('a', class_='xxx')
soup.find('a', title='xxx')
soup.find('a', id='xxx')
soup.find('a', id=re.compile(r'xxx'))

#find_all
#返回一个列表,列表里面是所有的符合要求的对象
soup.find_all('a')
soup.find_all('a', class_='wang')
soup.find_all('a', id=re.compile(r'xxx'))
soup.find_all('a', limit=2)   #提取出前两个符合要求的a

当然还有个select方法,这里我没有用,可自行采用了解!

#选择,选择器 css中

常用的选择器

标签选择器、id选择器、类选择器 层级选择器**

div h1 a 后面的是前面的子节点即可

div > h1 > a 后面的必须是前面的直接子节点

属性选择器 input[name='hehe'] select('选择器的') 返回的是一个列表,

列表里面都是对象 find find_all select不仅适用于soup对象,

还适用于其他的子对象,

如果调用子对象的select方法,

那么就是从这个子对象里面去找符合这个选择器的标签。

xpath解析

#xpath获取数据
def get_xmlsearch(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        html=etree.HTML(req)
        lis=html.xpath('//ul[@class="result"]/li[@class="res-list"]')
        for li in lis:
            title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理
            site_url=li.xpath('.//a[1]/@href')[0]
            try:
                pos=eval(li.xpath('.//a[1]/@data-res')[0])['pos']   #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")

re正则解析

#re正则获取数据
def get_research(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        ul=re.findall(r'<ul class="result">(.+?)<div id="side">',req,re.S)[0]
        lis=re.findall(r'<li class="res-list"(.+?)</li>',ul,re.S)
        for li in lis:
            title=re.findall(r'<a href=".+?>(.+?)</a>',li,re.S)[0]
            title=title.replace('<em>','').replace('</em>','') #标题字符串处理
            site_url=re.findall(r'<a href="(.+?)".+?>.+?</a>',li,re.S)[0]
            if "data-res" in li:
                pos=re.findall(r',"pos":(.+?),"m":',li,re.S)[0]
                pm = (i - 1) * 10 + int(pos)
            else:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")

运行效果:

测试就找到一个作弊站。。

附完整源码:

#360搜索排名查询
#20200108 by 微信:huguo00289
# -*- coding: utf-8 -*-

import requests,re,time
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
from lxml import etree


#构建协议头
def ua():
    ua=UserAgent()
    headers={
        'Cookie': 'QiHooGUID=622250714BFE7FEEBC7BE97B1768B7F1.1578470720454; _S=ilmjtet5usmi3a5005tq7of442; opqopq=d8a79fec6212514efe440041e132813c.1578470720',
        'Referer': 'https://www.so.com/haosou.html',
        "User-Agent":ua.random,
    }
    return headers

#获取访问数据
def get_html(url):
    response=requests.get(url,headers=ua(),timeout=10)
    print(response.status_code)
    req=response.content.decode('utf-8')
    return req

#获取搜索结果
#bs4获取数据
def get_bs4search(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        soup=BeautifulSoup(req,"html.parser")
        lis=soup.find("ul",class_="result").find_all("li",class_="res-list")
        print(len(lis))
        for li in lis:
            title=li.find("a").get_text()
            site_url=li.find("a")['href']
            try:
                pos=eval(li.find("a")['data-res'])['pos']  #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg=cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg !=[]:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")


#xpath获取数据
def get_xmlsearch(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        html=etree.HTML(req)
        lis=html.xpath('//ul[@class="result"]/li[@class="res-list"]')
        for li in lis:
            title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理
            site_url=li.xpath('.//a[1]/@href')[0]
            try:
                pos=eval(li.xpath('.//a[1]/@data-res')[0])['pos']   #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")



#re正则获取数据
def get_research(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        ul=re.findall(r'<ul class="result">(.+?)<div id="side">',req,re.S)[0]
        lis=re.findall(r'<li class="res-list"(.+?)</li>',ul,re.S)
        for li in lis:
            title=re.findall(r'<a href=".+?>(.+?)</a>',li,re.S)[0]
            title=title.replace('<em>','').replace('</em>','') #标题字符串处理
            site_url=re.findall(r'<a href="(.+?)".+?>.+?</a>',li,re.S)[0]
            if "data-res" in li:
                pos=re.findall(r',"pos":(.+?),"m":',li,re.S)[0]
                pm = (i - 1) * 10 + int(pos)
            else:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")


#查询网址是否存在排名
def cxwz(keyword,i,pm,title,site_url,cxurl):
    if cxurl in site_url:
        cxjg = f'关键词:{keyword},页码:第{i}页,排名:{pm},标题:{title},网址:{site_url}'
        print(f'关键词:{keyword},页码:第{i}页,排名:{pm},标题:{title},网址:{site_url}')
    else:
        cxjg=[]
    return cxjg


if __name__=="__main__":
    while True:
        keyword = input('请输入要查询的关键词:')
        num = input('请输入要查询的页码数:')
        url = input('请输入要查询的主域名:')
        try:
            get_bs4search(keyword,num,url)
        except IndexError as e:
            print(e)
            print("查询排名失败!")