最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Python3使用BeautifulSoup解析百度关键词搜索结果

代码案例 小楼一夜听春语 5793浏览 0评论

因为想看一下自己网站的关键词在百度搜索结果中的排名,所以,使用Python3编写了一个脚本进行爬取分析。

代码非常简单,水平一般(娇羞中),分享出来和大家交流。

先来说说实现过程吧!

一、百度搜索关键词的URL规则

例如:搜索本站域名“opython.com”。

搜索之后,点开搜索结果的第2页,URL类似:

https://www.baidu.com/s?wd=opython.com&pn=10&oq=opython.com&tn=baiduhome_pg&ie=utf-8&rsv_idx=2&rsv_pq=a99fa2280001734f&rsv_t=2b57Fux0BL2%2BdMJ6OjiZ6HP%2BE3OuYBUcSTarswtNJIr9qgkep2qSgUAMF0GOxB59Ja1o

为什么是第2页呢?

因为第1页看不到分页的参数。

这个URL是很长的一段内容,但实际上有用的就2个。

大家能够看到“https://www.baidu.com/s?”后面都是参数,真正有用的是“wd”和“pn”,也就是关键词和页码。

也许大家不太理解,为什么第2页的URL中参数“pn”的值是“10”。

这是因为搜索结果每一页的记录条数是10,这个数字代表当前页的搜索记录“id”是从10之后开始。

当我们了解了上述内容之后,就能够非常清楚的知道爬取某一个关键词搜索结果每一页的URL如何生成了。

格式:https://www.baidu.com/s?wd=[关键词]&pn=[页码减1乘10]

二、搜索结果的关键元素

百度的搜索结果页源代码中包含10条搜索记录。

但是,大家查看的时候,不要在浏览器中点鼠标右键选择查看源代码的选项,那样什么都看不到。

需要使用谷歌浏览器(Chrome)的检查或者火狐浏览器(Firefox)的审查元素功能才可以。

每一条搜索结果记录的内容类似:

<div class="result c-container " id="1" srcid="1599" tpl="se_com_default" data-click="{&quot;rsv_bdr&quot;:&quot;0&quot;,&quot;p5&quot;:1}">
...省略部分代码...
<a target="_blank" href="http://www.baidu.com/link?url=Ie_6NlHRiBISswMoiY1_LveUBXlni_TXQcf45SJmKjK" class="c-showurl" style="text-decoration:none;"><b>opython.com</b>/&nbsp;</a>
...省略部分代码...
百度快照</a></div></div>

代码太长,省略了无用的内容。

在保留的关键内容中,大家注意红字部分。

每条搜索结果记录的“id”是页面中唯一的,我们可以通过“id”来检查每条搜索记录是否包含查询的域名(关键词)。

但是,“id”是搜索记录最外层“<div>”标签的属性,我们还需要找到内部包含真实URL的“<a>”标签,获取它包含的字符串进行匹配。

这个包含真实URL的“<a>”标签,有一个“class”属性“c-showurl”,通过这个属性我们就能够比较准确的找到这个标签,并获取它内部包含的字符串。

不过要注意的是,获取到的字符串中会包含“<b>”标签,需要先清除掉。

因为有时被加粗的只是真实URL的一部分,导致我们不能获取到真实的地址。

例如,搜索“Python”这个关键词的时候,如果搜索结果记录中有“www.opython.com”这个地址,就会以“www.o<b>python</b>.com”的形式呈现。

三、模拟浏览器打开URL的行为

如果直接使用urllib库中request模块的urlopen()方法打开需要爬取的百度搜索页,是不能正常获取页面内容的。

得到的结果类似:

<html>
<head>
   <script>
      location.replace(location.href.replace("https://","http://"));
   </script>
</head>
<body>
   <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>

为了能够正常的获取搜索结果内容,我们需要模拟浏览器打开网页的行为。

这里使用request模块中的build_opener()方法,创建一个打开URL的工具对象,

示例代码:

opener = request.build_opener()

然后,为这个对象添加“header”信息。

示例代码:

opener.addheaders = [('User-agent',  # 添加模拟浏览器访问的header信息
                           'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11')]

“header”信息中的“User-Agent”是用于告诉远程服务器,客户端的软件环境。

最后,通过对象的open()方法打开URL获取页面内容。

示例代码:

html = self.opener.open(url).read().decode()

四、使用BeautifulSoup解析HTML

获取到的HTML内容,我们需要从中取得想要的信息。

BeautifulSoup是一个非常好用的用于解析HTML和XML的第三方库。

安装命令:

pip install beautifulsoup4

注意:使用这个库是“from bs4 import XXX”。

使用方法:

1、创建格式化后的文档对象

示例代码:

soup = BeautifulSoup(html, 'lxml')

注意:第二个参数“’lxml’”表示解析的是HTML。

2、通过文档对象进行查询操作

示例代码:

soup.p  # 获取文档对象中第1个<p>标签的内容
soup.p.string  # 获取文档中第1个<p>标签包含的字符串
soup.find(id=1)  # 获取文档对象中第1个“id”属性为“1”的标签
soup.find('a', 'c-showurl')  # 获取文档对象中“class”属性为“c-showurl”的<a>标签

更多使用帮助,请查看官方中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

五、最终实现

有了以上内容的支撑,我们就可以动手编写全部代码了。

示例代码:

from urllib import request
from urllib import parse
from bs4 import BeautifulSoup  # 用于解析HTML
import multiprocessing  # 用于多进程


class BaiduRanking:  # 定义爬取排名的类
    def __init__(self, words, page_number, domain):
        self.words = words  # 查询的关键词列表
        self.page_number = page_number  # 查询的页面数量
        self.domain = domain  # 查询的域名
        self.opener = request.build_opener()  # 创建打开URL的工具对象
        self.opener.addheaders = [('User-agent',  # 添加模拟浏览器访问的header信息
                                   'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11')]
        self.position = []  # 域名在搜索引擎查询结果中出现的位置列表

    def get_urls(self, word):  # 定义每个关键词查询页面的URL列表生成器
        urls = []
        for pn in range(self.page_number):
            url = 'https://www.baidu.com/s?wd=%s&pn=%s' % (parse.quote_plus(word), pn * 10)  # 注意关键词转换格式
            urls.append(url)
        yield urls

    def get_result(self, url, position, current_page):  # 定义获取排名结果的方法
        print(url)
        try:
            html = self.opener.open(url).read().decode().replace('<b>', '').replace('</b>', '')  # 获取页面内容并替换掉字体加粗标签
            soup = BeautifulSoup(html, 'lxml')  # 解析HTML
            for i in range(current_page * 10 + 1, current_page * 10 + 11):  # 轮询查询结果的id
                try:
                    if self.domain in soup.find(id=i).find('a', 'c-showurl').string:  # 判断从查询结果中找到的网址字符串是否包含域名
                        position.append(i)  # 添加查询结果id到位置列表
                except:  # 发生异常时继续查询
                    continue
        except:
            pass  # 某页面发生异常时忽略

    def run_task(self):  # 定义运行爬取任务的方法
        for word in self.words:  # 遍历关键词列表
            position = multiprocessing.Manager().list()  # 创建多进程共享的列表变量
            current_page = 0  # 当前查询的页面编号
            print('正在查询关键词:%s' % word)
            for urls in self.get_urls(word):  # 遍历当前关键词需要爬取的所有URL
                processes = multiprocessing.Pool(5)  # 开启进程池
                for url in urls:  # 遍历当前关键词的所有URL
                    processes.apply_async(self.get_result, args=(url, position, current_page))  # 为每个URL爬取任务创建进程
                    current_page += 1  # 页面编号自增
                processes.close()  # 关闭进程池
                processes.join()  # 等待进程结束
            print('查询完毕。\n出现位置:%s' % sorted(position))  # 显示输出排序后的爬取结果


if __name__ == '__main__':
    domain = 'opython.com'  # 查询的域名
    words = ['Django2教程', 'Python新手教程']  # 查询的关键词列表
    page_number = 10  # 每个关键词爬取的页面数量
    ranking = BaiduRanking(words=words, domain=domain, page_number=page_number)  # 实例化爬取排名的对象
    ranking.run_task()  # 运行爬取任务

转载请注明:魔力Python » Python3使用BeautifulSoup解析百度关键词搜索结果

与本文相关的文章

  • 暂无相关文章!
头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (1)

  1. 头像
    感谢分享! 试运行了您的代码,“出现位置:[]”,出现位置这里显示的是空列表,但是我手动查过,这个url在某个关键词下是确确实实有排名的啊,这个咋回事呢
    万里长沙6年前 (2018-10-23)回复