爬取百度搜索结果的爬虫

来源:互联网 发布:java web工作流开发 编辑:程序博客网 时间:2024/05/02 00:47

(本文原作于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    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\=.*?)"', 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)==1:                self.next_page_url = 'https://www.baidu.com'+next[0]            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()

PS: 欢迎访问我的独立博客:远山曲 https://blog.werner.wiki/