爬取百度搜索结果的爬虫

(本文原作于2017年4月4日)

是这样的,在所谓的网络空间搜索引擎钟馗之眼搜索某cms名称,发现搜索结果只有可怜的17条,而在百度搜索“”Powered by 某cms””,结果有约2,150个,差距还是很大的。而去国外的那个撒旦搜这个cms,结果直接为“No results found”。好吧,还得靠百度。

为便于程序自动化处理搜索结果,便产生了写一个Python脚本来自动搜索的想法。要求输入搜索关键词和页数,输出百度搜索此关键词所得结果的前某某页中的指向搜索结果的链接。

难点有二,一是百度搜索结果中的链接都不是直接指向搜索结果的,而是:

    http://www.baidu.com/link?url=N5vu2VW2jp1E4lIDBiL77-J2B65YL9MgyXC0YmJNdjW

这种样子的,需要再处理才行。二是翻页问题,现在百度搜索结果的翻页不再由url中的参数pn来控制,在以前,pn=2便是搜索结果的第二页,pn=5便是搜索结果的第5页,现在不清楚是怎么控制翻页的,我研究也好久也没弄明白。

第一个问题的解决是这样的,先拿到会跳转的链接,然后打开它,会发现HTTP状态码是302,从HTTP头的location字段中便可以取到目标链接。第二个问题的解决是取巧的,每个爬取的页面总有下一页的按钮,直接解析出下一页的按钮对应的url,便拿到了下一页的url。

给这个脚本命名为baidu_crawler.py,有三个参数,-k是必须的,后接搜索关键词,-t后接一个整数,是超时时间,默认为60秒,-p后接一个整数,是要爬取的总页数,默认为5页。如在终端中输入如下命令:

    python baidu_crawler.py -k inurl:asp?id= -p 2

其输出结果为:

    http://www.newmen.com.cn/product/product.asp?id=664
    http://fanyi.baidu.com/?aldtype=23&keyfrom=alading#en/zh/inurl%3Aasp%3Fid
    http://fanyi.baidu.com/?aldtype=23#en/zh/inurl%3Aasp%3Fid
    http://www.ampcn.com/show/index.asp?id=225238
    http://www.jmzjzc.com/news.asp?id=1296
    http://www.youda999.com/NewsView.Asp?ID=1818&SortID=10
    http://www.kjcxpp.com/tebie.asp?id=4987
    http://www.szxcc.com/gb/about1_xinxi.asp?id=325
    http://www.synsun.com.cn/IntotheformerSt.asp?id=15
    http://www.yorku.org.cn/displaynews1_new.asp?id=63
    http://www.luoxin.cn/newsinfo.asp?id=8623
    http://dfgjt.com/show_news.asp?id=515
    http://jsxx.ahau.edu.cn/jsxx_show.asp?ID=1995046
    http://www.fjplan.org/chgnr.asp?id=227
    http://chem.xmu.edu.cn/show.asp?id=1995
    http://www.nhzupei.com/viewanli.asp?id=556
    http://www.snsafety.gov.cn/admin/pub_newsshow.asp?id=1040041&chid=100118
    http://www.cnarts.net/cweb/news/read.asp?id=317959
    http://www.zjgjgs.com/news_view.asp?id=964
    http://www.sanheip.com/about.Asp?id=3
    http://www.cqgbc.org/news_x.asp?id=403

下面是这个程序的源代码:

#!/usr/bin/python
# ^_^ coding:utf8 ^_^

import re
import requests
import traceback
from urllib import quote
import sys, getopt
reload(sys)
sys.setdefaultencoding('utf-8')

class crawler:
    '''爬百度搜索结果的爬虫'''
    url = u''
    urls = []
    o_urls = []
    html = ''
    total_pages = 5
    current_page = 0
    next_page_url = ''
    timeout = 60                    #默认超时时间为60秒
    headersParameters = {    #发送HTTP请求时的HEAD信息,用于伪装为浏览器
        'Connection': 'Keep-Alive',
        'Accept': 'text/html, application/xhtml+xml, */*',
        'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
        'Accept-Encoding': 'gzip, deflate',
        'User-Agent': 'Mozilla/6.1 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
    }

    def __init__(self, keyword):
        self.url = u'https://www.baidu.com/baidu?wd='+quote(keyword)+'&tn=monline_dg&ie=utf-8'

    def set_timeout(self, time):
        '''设置超时时间,单位:秒'''
        try:
            self.timeout = int(time)
        except:
            pass

    def set_total_pages(self, num):
        '''设置总共要爬取的页数'''
        try:
            self.total_pages = int(num)
        except:
            pass

    def set_current_url(self, url):
        '''设置当前url'''
        self.url = url

    def switch_url(self):
        '''切换当前url为下一页的url
           若下一页为空,则退出程序'''
        if self.next_page_url == '':
            sys.exit()
        else:
            self.set_current_url(self.next_page_url)

    def is_finish(self):
        '''判断是否爬取完毕'''
        if self.current_page >= self.total_pages:
            return True
        else:
            return False

    def get_html(self):
        '''爬取当前url所指页面的内容,保存到html中'''
        r = requests.get(self.url ,timeout=self.timeout, headers=self.headersParameters)
        if r.status_code==200:
            self.html = r.text
            self.current_page += 1
        else:
            self.html = u''
            print '[ERROR]',self.url,u'get此url返回的http状态码不是200'

    def get_urls(self):
        '''从当前html中解析出搜索结果的url,保存到o_urls'''
        o_urls = re.findall('href\=\"(http\:\/\/www\.baidu\.com\/link\?url\=.*?)\" class\=\"c\-showurl\"', self.html)
        o_urls = list(set(o_urls))  #去重
        self.o_urls = o_urls
        #取下一页地址
        next = re.findall(' href\=\"(\/s\?wd\=[\w\d\%\&\=\_\-]*?)\" class\=\"n\"', self.html)
        if len(next) > 0:
            self.next_page_url = 'https://www.baidu.com'+next[-1]
        else:
            self.next_page_url = ''

    def get_real(self, o_url):
        '''获取重定向url指向的网址'''
        r = requests.get(o_url, allow_redirects = False)    #禁止自动跳转
        if r.status_code == 302:
            try:
                return r.headers['location']    #返回指向的地址
            except:
                pass
        return o_url    #返回源地址

    def transformation(self):
        '''读取当前o_urls中的链接重定向的网址,并保存到urls中'''
        self.urls = []
        for o_url in self.o_urls:
            self.urls.append(self.get_real(o_url))

    def print_urls(self):
        '''输出当前urls中的url'''
        for url in self.urls:
            print url

    def print_o_urls(self):
        '''输出当前o_urls中的url'''
        for url in self.o_urls:
            print url

    def run(self):
        while(not self.is_finish()):
            c.get_html()
            c.get_urls()
            c.transformation()
            c.print_urls()
            c.switch_url()

if __name__ == '__main__':
    help = 'baidu_crawler.py -k  [-t  -p ]'
    keyword = None
    timeout  = None
    totalpages = None
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hk:t:p:")
    except getopt.GetoptError:
        print(help)
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print(help)
            sys.exit()
        elif opt in ("-k", "--keyword"):
            keyword = arg
        elif opt in ("-t", "--timeout"):
            timeout = arg
        elif opt in ("-p", "--totalpages"):
            totalpages = arg
    if keyword == None:
        print(help)
        sys.exit()

    c = crawler(keyword)
    if timeout != None:
        c.set_timeout(timeout)
    if totalpages != None:
        c.set_total_pages(totalpages)
    c.run()

PS: 欢迎访问我的独立博客:若水斋 https://blog.werner.wiki/

你可能感兴趣的:(编程)