爬取百度搜索结果的爬虫

是这样的,在所谓的网络空间搜索引擎钟馗之眼搜索某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 <keyword> [-t <timeout> -p <total pages>]'
        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()

One Reply to “爬取百度搜索结果的爬虫”

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

15 + 15 =