简明Python开发教程(5):用爬虫实现个性化搜索引擎

相信大家都遇到一个问题——百度搜索的结果可能50%都是广告,今天我们尝试搭建一个个性化搜索引擎。
我们使用网络爬虫来解决该问题,从自动搜索、抓取网页,提取网页内容、按照个性化匹配内容,输出保存,模拟搜索引擎的工作工程。
Python在网络爬虫方面也有很多成熟的库,也有很好的框架可以提供。

Python网络爬虫

Python网络爬虫,通过Python自动获取url的网页html内容,然后用正则表达式分析html,得到你想要的内容,包括url、文字、图片等。
如果必要,就可以对网页内url进行分析,进一步爬取,直到获得自己想要的内容。
当然通过文本语义分析,判断该网页是否是自己想要的内容也很重要。

Python爬取百度首页

今天我们用python3自带的urllib获取url内容。urllib是一组处理URLs的包,其中request模块可以打开和读取url链接。
我们看一下最简单的百度首页爬取示例。

from urllib import request
response = request.urlopen("http://www.baidu.com/") #打开百度首页
html = response.read()  #读取响应值
html = html.decode('utf-8')   #需要解码decode后,才能正常显示。编码方式可以通过网页查询

我们通过可以查看html的详细内容,如

In[23]: html[:20]
Out[23]: '<!DOCTYPE html>\n<!--'

也可以保存为本地html文件,离线查看。

Python处理html

Chorme浏览器开发者模式

Python可以用正则表达式提取想要的内容,在这之前建议通过chorme分析下待爬取的网页。
假如我们想提取百度首页右上角常用导航名称及url。通过开发者模式右上角箭头点击网页感兴趣内容,可以快速定位到源代码部分。

image.png

我们看一下该部分html源码:

<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews" class="mnav" saprocessedanchor="true">新闻</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav" saprocessedanchor="true">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav" saprocessedanchor="true">地图</a>
......
</div>

正则表达式处理HTML

然后我们就可以很容易写出提取标题的url和标题的正则表达式:

#没有办法一次性提取,先提问导航栏的全部内容
patten_u1 = re.compile('<div id="u1">.*?</div>',re.S)
item = patten_u1.findall(html)
#然和提取每一个导航链接
patten = re.compile(r'<a href="(?P<url>.*?)".*?class="mnav".*?>(?P<title>.*?)</a>',re.S)
items = patten.findall(item[0])

我可以看一下输出结果,非常完美。

In[50]:items
Out[50]: 
[('http://news.baidu.com', '新闻'),
 ('http://www.hao123.com', 'hao123'),
 ('http://map.baidu.com', '地图'),
 ('http://v.baidu.com', '视频'),
 ('http://tieba.baidu.com', '贴吧'),
 ('http://xueshu.baidu.com', '学术')]

BeautifulSoup快速处理HTML

前面我们说过,Python的强大之处就是有很多“轮子”,可以直接拿来使用。正则表达式处理网页还是非常复杂的,不同网页必须重新写,而已经有人造好BeautifulSoup轮子,可以快速处理HTML,转换为Python对象,直接处理。
BeautifulSoup的使用有很多教程,需要大家自己学习,我也刚刚入门。
上面的功能可以快速实现:

from bs4 import BeautifulSoup   #导入库
soup = BeautifulSoup(html, 'lxml')   #转换html文件为BS对象
#安装逻辑选择,首先过滤 mnav,然和遍历,分别获取url和名称
items =[(i.attrs['href'],i.text) for i in soup.select('.mnav')]  

结果和之间一样。大家可以尝试一下soup.select('.mnav')、soup.select('.mnav')[0].attrs的内容,理解BeautifulSoup的使用技巧。

Python实现个性化搜索引擎

上面已经基本了解Python爬虫的基本操作和所需知识,下面我尝试搭建个性化搜索引擎爬虫的基本框架。
经过初步分析,应该有以下几个功能点:

  • 接受若干关键字,以空格区分,用百度搜索网页
  • 分析网页内容,提取网页标题、url、简介,快速过滤广告、和关键字无关url
  • 输出目标url、标题和简介供用户参考。
    最终代码如下:
from urllib import request
from urllib import parse
from bs4 import BeautifulSoup
import pandas as pd
import re
import sys
#给定url,获取对应html,已经解码后
def get_html(url):
    head = {}
    head['User-Agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36"
    #模拟浏览器,可以简单避免反爬虫
    req = request.Request(url, headers=head)
    response = request.urlopen(req)    
    html = response.read()
    #获取网页编码方式
    charset = response.info().get_param('charset')
    html = html.decode(charset)
    return html
#从百度搜索页面结果,获取下一页url地址
def get_next_url(html):
    soup = BeautifulSoup(html, 'lxml')
    n = soup.select('.n')
    if len(n) ==1:
        url = n[0].attrs['href']
    elif len(2) ==2:
        url = n[1].attrs['href']
    return "https://www.baidu.com"+url
    
#用百度网页搜索关键字,返回前nums页的html
def get_baidu_keywb(wb,nums):
    url = "https://www.baidu.com/s?wd={}".format(parse.quote(wb))
    htmls = []
    html = get_html(url)
    htmls.append(html)
    #读取下一页,直到指定页数
    i = 1
    while(i<nums):
        url_next = get_next_url(html)
        html = get_html(url_next)
        htmls.append(html)
        i = i+1
    return htmls

#分析处理htmls,得到一个表格,列名:标题、简介、详细url
def anay_htmls(htmls):
    rows = []
    for html in htmls:
        soup = BeautifulSoup(html, 'lxml')
        for i in soup.select('.result'):
            patten = re.compile(r'{"title":"(.*?)","url":"(.*?)"}',re.S)
            if 'c-abstract' in str(i):
                data_tools = patten.findall(i.select('.c-tools')[0].attrs['data-tools'])[0]
                title = data_tools[0]
                detail_url = data_tools[1]
                text = i.select('.c-abstract')[0].text
                row = [title,text,detail_url]
                rows.append(row)
    data = pd.DataFrame(rows,columns=['title','text','detail_url'])
    return data

#按照关键字过滤网页,按照某种优先级排序,这里算法可以很智能,需要搭建完善
#可以增加更多更智能的处理逻辑
def  filter_urls(data,wb):
    key_wb = wb.split(" ")
    #百度关键字搜索不一定对,如搜广东移动,可能出现移动,进一步强匹配
    isbaoliu = []
    for i in data.index:
        flag = True #是否保留标志
        title = data.loc[i]['title']
        text = data.loc[i]['text']
        #多个关键字同时出现在标题或简介中
        for key in key_wb:
            #只要一个关键字不在 title和text中,置否
            if (key not in title) & (key not in text):
                flag =False
                break
        isbaoliu.append(flag)
    data_out = data[isbaoliu]
    return data_out

if __name__ =='__main__':
    if len(sys.argv) > 2:
        nums = int(sys.argv[1])
        wb = ' '.join(sys.argv[2:])
        htmls = get_baidu_keywb(wb,nums)  #用百度查询网页
        data = anay_htmls(htmls)  #分析网页
        data_out = filter_urls(data,wb) #过滤网页
        #输出过滤后结果,仅作测试,真实代码可以不要这句
        print("搜索过滤后结果{}条,比百度搜索少{}%。".format(len(data_out),'%0.2f' % (100*(len(data)-len(data_out))/float(len(data)))))
        filename = "查询结果_"+wb.replace(' ','_') +".csv"
        data_out.to_csv(filename,encoding = 'utf-8-sig',index = False)
        
    else:
        print("请输入查询页数及关键字,以空格区分关键字,比如\npython crawler_demo.py 2 广东移动 IPTV")

然后可以在命令行执行我们的个性化搜索引擎。

image.png
image.png

上面广告已经自动过滤调,同时减少68%的无效信息,个性化搜索引擎可以更适合自己,毕竟自己写的哈。
当然这个程序还有很多完善的地方,比喻语义分析相关,有一个分词的库——jieba分词,我同样没有时间去学。欢迎大家补充。
Python有个强大的爬虫框架Scrapy。非常强大,我也没时间去学。这些都期待你们的分享。
下一期,我们聊聊用Python进行网站搭建——简明Python开发教程(6):用Django搭建网站(https://www.jianshu.com/p/f5eb5a6864ed)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容