精华内容
下载资源
问答
  • 新版中国天气爬虫 获取最新天气 以及天气日历数据 Conky Linux
  • 爬虫陷阱

    2018-11-10 10:24:00
    比如,网站有一个在线日历功能,提供了可以访问下个月和下一年的链接,那么下个月的页面中同样会包含访问再下个月的链接,这样页面就会无止境地链接下去,这种情况被称为爬虫陷阱。 想要避免陷入爬虫陷阱,一个简单...

    目前,我们的爬虫会跟踪所有之前没有访问过的链接。但是,一些网站会动态生成页面内容,这样就会出现无限多的网页。比如,网站有一个在线日历功能,提供了可以访问下个月和下一年的链接,那么下个月的页面中同样会包含访问再下个月的链接,这样页面就会无止境地链接下去,这种情况被称为爬虫陷阱。

    想要避免陷入爬虫陷阱,一个简单的方法是记录到达当前网页经过了多少个链接,也就是深度。当到达最大深度时, 爬虫就不再向队列中添加该网页中的链接了。要实现这一功能, 我们需要修改seen变量。该变量原先只记录访问过的网页链接,现在修改为一个字典,增加了页面深度的记录。

    import urllib.request
    import urllib.error 
    import re #正则表达式
    import urllib.parse #将url链接从相对路径(浏览器可懂但python不懂)转为绝对路径(python也懂了)
    import urllib.robotparser #爬取数据前解析网站robots.txt文件,避免爬取网站所禁止或限制的
    import datetime  #下载限速功能所需模块
    def download(url, user_agent = "brain", proxy = None, num_retries = 2):  #下载url网页,proxy是支持代理功能,初始值为None,想要设置就直接传参数即可
        print("downloading:",url)
        header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6
        req = urllib.request.Request(url, headers = header)    
        
        opener = urllib.request.build_opener()  #为支持代理功能时刻准备着
        if proxy:   #如果设置了proxy,那么就进行以下设置以实现支持代理功能
            proxy_params = { urllib.parse.urlparse(url).scheme: proxy }
            opener.add_handler(urllib.request.ProxyHandler(proxy_params))
            response = opener.open(req)
            
        try:
            html = urllib.request.urlopen(req).read()
        except urllib.error.URLError as e:    #下载过程中出现问题
            print("download error:",e.reason)
            html = None
    
            if num_retries > 0:     #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载
                if hasattr(e, "code") and 500<= e.code <600:
                    return  download(url, user_agent, num_retries-1)  # recursively retry 5XX HTTP errors
        return html
    #跟踪链接的爬虫
    #link_crawler()函数传入两个参数:要爬取的网站URL、用于跟踪链接的正则表达式。
    def link_crawler(seed_url, link_regex, max_depth=2):
        """先下载 seed_url 网页的源代码,然后提取出里面所有的链接URL,接着对所有匹配到的链接URL与link_regex 进行匹配,
    如果链接URL里面有link_regex内容,就将这个链接URL放入到队列中,
    下一次 执行 while crawl_queue: 就对这个链接URL 进行同样的操作。
    反反复复,直到 crawl_queue 队列为空,才退出函数。"""
        crawl_queue = [seed_url]
        max_depth = 2 #为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数;如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等
        seen = {seed_url:0} #初始化seed_url访问深度为0
        
        #seen = set(crawl_queue) #有可能链接中互相重复指向,为避免爬取相同的链接,所以我们需要记录哪些链接已经被爬取过(放在集合seen中),若已被爬取过,不再爬取
        while crawl_queue:
            url = crawl_queue.pop()
            
            rp = urllib.robotparser.RobotFileParser()   #爬取前解析网站robots.txt,检查是否可以爬取网站,避免爬取网站禁止或限制的
            rp.set_url("http://example.webscraping.com/robots.txt")
            rp.read()
            user_agent = "brain"
            if rp.can_fetch(user_agent, url):  #解析后发现如果可以正常爬取网站,则继续执行
                
                #爬取网站的下载限速功能的类的调用,每次在download下载前使用
                throttle = Throttle(delay=5) #这里实例网站robots.txt中的delay值为5
                throttle.wait(url)
                html = download(url)   #html = download(url, hearders, proxy=proxy, num_retries=num_retries)这里可以传所需要的参数
                
                html = str(html)
                #filter for links matching our regular expression
                if html == None:
                    continue
    
                depth = seen[url]  #用于避免爬虫陷阱的记录爬取深度的depth
                if depth != max_depth:
                    for link in get_links(html):
                        if re.match(link_regex, link):
                            link = urllib.parse.urljoin(seed_url, link) #把提取的相对url路径link(view/178)转化成绝对路径(/view/Poland-178)link
                            if link not in seen:  #判断是否之前已经爬取
                                seen[link] = depth + 1 #在之前的爬取深度上加1
                                crawl_queue.append(link) #之前没有的话这个链接可用,放在列表中继续进行爬取
            else:
                print("Blocked by %s robots,txt" % url)
                continue
            
    def get_links(html):
        """用来获取一个html网页中所有的链接URL"""
        #做了一个匹配模板 webpage_regex,匹配 <a href="xxx"> or <a href='xxx'>这样的字符串,并提取出里面xxx的URL,请注意这里的xxxURL很可能是源码中相对路径,eg view/1 正常访问肯定是打不开的
        webpage_regex = re.compile('<a href=["\'](.*?)["\']', re.IGNORECASE)
        return re.findall(webpage_regex,html)
        #return re.findall('<a[^>]+href=["\'](.*?)["\']', html)也可以这样实现,但没有上面的先编译模板再匹配好
    
    class Throttle:  #爬取网站的下载限速功能的类的实现,每次在download下载前使用
        """Add a delay between downloads to the same domain"""
        def __init__(self, delay):
            self.delay = delay  # value of delay between downloads for each domain
            self.domains = {}   # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
    
        def wait(self, url):
            domain = urllib.parse.urlparse(url).netloc
            last_accessed = self.domains.get(domain)
    
            if self.delay>0 and last_accessed is not None:
                sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).seconds
                if sleep_secs > 0:
                    time.sleep(sleep_secs)  #domain has been accessed recently,so need to sleep
            self.domains[domain] = datetime.datetime.now()
    
    #只想找http://example.webscraping.com/index... or http://example.webscraping.com/view...
    link_crawler("http://example.webscraping.com", "/(index|view)")

    #跟踪链接的爬虫 #link_crawler()函数传入两个参数:要爬取的网站URL、用于跟踪链接的正则表达式。 def link_crawler(seed_url, link_regex, max_depth=2): """先下载 seed_url 网页的源代码,然后提取出里面所有的链接URL,接着对所有匹配到的链接URL与link_regex 进行匹配, 如果链接URL里面有link_regex内容,就将这个链接URL放入到队列中, 下一次 执行 while crawl_queue: 就对这个链接URL 进行同样的操作。 反反复复,直到 crawl_queue 队列为空,才退出函数。""" crawl_queue = [seed_url] max_depth = 2 #为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数;如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等 seen = {seed_url:0} #初始化seed_url访问深度为0 #seen = set(crawl_queue) #有可能链接中互相重复指向,为避免爬取相同的链接,所以我们需要记录哪些链接已经被爬取过(放在集合seen中),若已被爬取过,不再爬取 while crawl_queue: url = crawl_queue.pop() rp = urllib.robotparser.RobotFileParser() #爬取前解析网站robots.txt,检查是否可以爬取网站,避免爬取网站禁止或限制的 rp.set_url("http://example.webscraping.com/robots.txt") rp.read() user_agent = "brain" if rp.can_fetch(user_agent, url): #解析后发现如果可以正常爬取网站,则继续执行 #爬取网站的下载限速功能的类的调用,每次在download下载前使用 throttle = Throttle(delay=5) #这里实例网站robots.txt中的delay值为5 throttle.wait(url) html = download(url) #html = download(url, hearders, proxy=proxy, num_retries=num_retries)这里可以传所需要的参数 html = str(html) #filter for links matching our regular expression if html == None: continue depth = seen[url] #用于避免爬虫陷阱的记录爬取深度的depth if depth != max_depth: for link in get_links(html): if re.match(link_regex, link): link = urllib.parse.urljoin(seed_url, link) #把提取的相对url路径link(view/178)转化成绝对路径(/view/Poland-178)link if link not in seen: #判断是否之前已经爬取 seen[link] = depth + 1 #在之前的爬取深度上加1 crawl_queue.append(link) #之前没有的话这个链接可用,放在列表中继续进行爬取 else: print("Blocked by %s robots,txt" % url) continue def get_links(html): """用来获取一个html网页中所有的链接URL""" #做了一个匹配模板 webpage_regex,匹配 <a href="xxx"> or <a href='xxx'>这样的字符串,并提取出里面xxx的URL,请注意这里的xxxURL很可能是源码中相对路径,eg view/1 正常访问肯定是打不开的 webpage_regex = re.compile('<a href=["\'](.*?)["\']', re.IGNORECASE) return re.findall(webpage_regex,html) #return re.findall('<a[^>]+href=["\'](.*?)["\']', html)也可以这样实现,但没有上面的先编译模板再匹配好 class Throttle: #爬取网站的下载限速功能的类的实现,每次在download下载前使用 """Add a delay between downloads to the same domain""" def __init__(self, delay): self.delay = delay # value of delay between downloads for each domain self.domains = {} # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。 def wait(self, url): domain = urllib.parse.urlparse(url).netloc last_accessed = self.domains.get(domain) if self.delay>0 and last_accessed is not None: sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).seconds if sleep_secs > 0: time.sleep(sleep_secs) #domain has been accessed recently,so need to sleep self.domains[domain] = datetime.datetime.now() #只想找http://example.webscraping.com/index... or http://example.webscraping.com/view... link_crawler("http://example.webscraping.com", "/(index|view)")

     

    转载于:https://www.cnblogs.com/navysummer/p/9938533.html

    展开全文
  • 爬虫基本知识 这阵子需要用爬虫做点事情,于是系统的学习了一下python爬虫,觉得还挺有意思的...人生日历截图20160513201530.png 爬虫的功能就是把网页源代码想办法爬下来,然后分析出需要的内容。总结起来就是2个...

    爬虫基本知识


    这阵子需要用爬虫做点事情,于是系统的学习了一下python爬虫,觉得还挺有意思的,比我想象中的能干更多的事情,这里记录下学习的经历。

    网上有关爬虫的资料特别多,写的都挺复杂的,我这里不打算讲什么大道理,因为其实爬虫挺好理解的。就是下面一个流程:

    人生日历截图20160513201530.png

    爬虫的功能就是把网页源代码想办法爬下来,然后分析出需要的内容。总结起来就是2个部分:

    1. 提取

    所以,整个爬虫需要掌握的技能,就是如何高效的爬,如何快速的分析提取所需要的内容。

    如何爬?

    Requests

    说实话,之前为了找爬虫的教程,走了挺多弯路的,因为现在很多教程刚上来就介绍urllib,urllib2这两个python自带的有关网页的包,所以刚开始我的单线程爬虫实现也都是基于urllib的,不仅代码多,而且效率还低。实际上,目前来说,这两个已经很过时了,目前用的比较多的是requests这个第三方包(这里我也是偶然间发现极客学院有关爬虫的视频,让我少走那么多弯路,这里我就不说是什么视频了,以免有广告的嫌疑,大家有兴趣的可以自己去搜)。
    正如requests的官方网页说的:

    Requests: HTTP for Humans

    它目前应该是python下最好的Http库了。它还有很多别的特性:

    Requests 使用的是 urllib3,继承了urllib2的所有特性。Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。

    上面介绍的是单线程爬虫,然后,如果要提高爬的效率,并行化肯定必不可少,那么scrapy就可以解决你的问题。然后还有js动态加载的问题。那些我以后也会慢慢加上来。

    Requests安装

    pip install requests
    

    所有的python第三方包的安装都可以用pip,如果cmd中无法输入pip命令,请把C:\Python27\Scripts加入PATH环境变量。

    注:这里不推荐使用easy_install 因为这个只管安装,不管卸载。

    Requests使用

    基本知道一个requests.get()和requests.post()就行了。

    同样它还有
    requests.head()
    requests.delete()
    功能,不过用的不多。需要的时候,查手册就好了。
    这里有个文档写requests写的挺全面的。可以看看:requests快速上手

    requests的返回值可以有多种形式输出,最常用的是
    “.text”和".content",前者输出unicode,后者输出二进制

     import requests  
     url = 'http://www.baidu.com'
     html = requests.get(url)
     print html.text
    

    输出:

    <!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta content="always" name="referrer"><meta name="theme-color" content="#2932e1"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" /><link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu.svg"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/><link rel="dns-prefetch" href="//t3.baidu.com"/><link rel="dns-prefetch" href="//t10.baidu.com"/><link rel="dns-prefetch" href="//t11.baidu.com"/><link rel="dns-prefetch" href="//t12.baidu.com"/><link rel="dns-prefetch" href="//b1.bdstatic.com"/><title>百度一下,你就知道</title>
    ……
    ……
    

    如何提取?

    正则表达式

    正则表达式是一个大头!很多也都听过正则表达式,第一印象就是记不住,但是其实也不用特别记忆,因为在爬虫里,用的最多的基本就一个

    (.*?)
    

    ( ) :表示这个内容是我们需要提取的
    .* :表示匹配任意字符0到n次
    ?:表示非贪心,找对第一个就停下来

    我来解释下为什么在爬虫里只要这个pattern就行了。
    在html网页源代码中,我们需要找的内容一般都是被某些标签包围的,如果我们能保证找到我们需要的内容左右的标签(并且他们是独一无二的)那么我们很容易写出一个正则表达式:

    <XXX>(.*?)</XXX>
    

    把其中的内容提取出来

    python正则模块使用

    python的正则模块是re,主要用的函数是(re.S的意思是让"."可以匹配换行符,不然有些标签头和尾是分几行的,就会匹配失败)

    findall(pattern,str,re.S)
    

    主力部队,把所有满足正则的内容提取出来,用于匹配满足某个条件的大量我们需要的内容。(比如所有的图片,所有的网址,所有的回复,所有的链接……)。它在网页提取中占了主要地位,工作量大,任务重,所以是主力部队。

    search(pattern,str,re.S)
    

    狙击手,用来匹配第一个找到的元素,它的目标目的就是找到我们明显知道只有一个的元素比如标题什么的,一旦找到就结束,所以它的执行速度很快。它的目标明确,效率高,所以是狙击手的角色。

    sub(pattern,str,replace)
    

    后勤,它的功能是替换,一般用于替换一个网页地址中的关键词,替换页码等。它看似不重要,但是往往能在很多方面给我们提供便利,所以是后勤。

    注意:正则有时候一步不能完成我们需要的功能,可能需要进行几步操作,这时候,我们一般先提取大的部分,在从大部分里面提取我们需要的部分

    我们看个很简单的例子:

    import re
    
    #假设下面是一个源码,我想保存里面所有的链接
    text = '<a href = "www.baidu.com">....'
    urls = re.findall('<a href = (.*?)>',text,re.S)
    for each in urls:
        print each
    
    #假设我需要爬取当前网页的头部
    html = '''
    <html>
    <title>爬虫的基本知识</title>
    <body>
    ……
    </body>
    </html>
    '''
    print re.search('<title>(.*?)</title>',html,re.S).group(1)
    #这里group(1)表示第一个括号的内容,如果正则里面有多个括号,这里可以通过group(i)返回第i个空格里的内容
    
    
    
    #假设下面是一个贴吧的帖子地址,有很多页,每一页就是靠后面的pn=几来区分的,我们输出前10页的网址
    Pages = 'http://tieba.baidu.com/p/4342201077?pn=1'
    for i in range(10): 
        print re.sub('pn=\d','pn=%d'%i,Pages)
    
    

    输出:

    "www.baidu.com"
    爬虫的基本知识
    http://tieba.baidu.com/p/4342201077?pn=0
    http://tieba.baidu.com/p/4342201077?pn=1
    http://tieba.baidu.com/p/4342201077?pn=2
    http://tieba.baidu.com/p/4342201077?pn=3
    http://tieba.baidu.com/p/4342201077?pn=4
    http://tieba.baidu.com/p/4342201077?pn=5
    http://tieba.baidu.com/p/4342201077?pn=6
    http://tieba.baidu.com/p/4342201077?pn=7
    http://tieba.baidu.com/p/4342201077?pn=8
    http://tieba.baidu.com/p/4342201077?pn=9
    
    

    XPath

    如果说正则表达式就已经让你觉得很神奇了,那XPath真是要吓死你了。这真是个神器,它让提取信息网页信息变得更加轻松。XPath是一个树型的结构,比较符合“html”的层次结构。

    XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSLT间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。

    我觉得视频中老师的解释超精彩:如果你提取信息就像让你找一栋建筑,那么正则就是告诉你建筑左边是什么,右边是什么,但是全国可能有很多都满足条件的,你找起来还是不方便。

    红房子(.*?)绿房子
    

    XPath就是告诉你,这个建筑在北京市——海淀区——中关村——15号街——那栋黄色的建筑,你可以马上找到对应的建筑。如果一个地名只有一个地方有,那么你更可以简化成“中关村——15号街”

    //北京市/海淀区/中关村/15号街[@房子颜色=黄色]/text()
    //中关村/15号[@房子颜色=黄色]/text()
    

    也许在这里你还没能体会到他们之间的差别,但是相信我,当你遇到复杂的html分析的时候,你会发现它的厉害之处的。比如下面的例子,我想把Hello,my world!打印出来用正则需要考虑一下吧?但是用XPath就简单很多

    <div id="class">Hello,
        <font color=red>my
        world!
    <div>
    

    XPath语法

    XPath你只需要知道这些语法

    // 根节点
    / 下一层路径
    [@XX=xx] 特定的标签

    /text() 以文本返回
    /@para 返回参数

    string(.) 当前层的所有内容作为一个字符串输出
    start-with(str) 所有以这个str开头的标签

    下面是一个简单的例子

    from lxml import etree
    html=
    '''
    <div id="test1">content1</div>
    <div id="test2">content2</div>
    <div id="test3">content3</div>
    '''
    
    selector = etree.HTML(html)
    content = selector.XPath('//div[start-with(@id,"test")]/text()')
    for each in content:
        print each
    
    html1=
    '''
    <div id="class">Hello,
        <font color=red>my</font>
        world!
    <div>
    '''
    
    selector = etree.HTML(html)
    tmp = selector.XPath('//div[@id="class"]')[0]
    info = tmp.XPath('string(.)')
    content2 = info.replace('\n','')
    print content2
    

    输出:

    content 1
    content 2
    content 3
    Hello,        my        world!  
    



    转自:https://www.jianshu.com/p/74b94eadae15

    展开全文
  • 爬取网站前4_避免爬虫陷阱

    千次阅读 2017-05-19 13:44:20
    比如,网站有一个在线日历功能,提供了可以访问下个月和下一年的链接,那么下个月的页面中同样会包含访问再下个月的链接,这样页面就会无止境地链接下去,这种情况被称为爬虫陷阱。 想要避免陷入爬虫陷阱,一个简单...

    目前,我们的爬虫会跟踪所有之前没有访问过的链接。但是,一些网站会动态生成页面内容,这样就会出现无限多的网页。比如,网站有一个在线日历功能,提供了可以访问下个月和下一年的链接,那么下个月的页面中同样会包含访问再下个月的链接,这样页面就会无止境地链接下去,这种情况被称为爬虫陷阱。

    想要避免陷入爬虫陷阱,一个简单的方法是记录到达当前网页经过了多少个链接,也就是深度。当到达最大深度时, 爬虫就不再向队列中添加该网页中的链接了。要实现这一功能, 我们需要修改seen变量。该变量原先只记录访问过的网页链接,现在修改为一个字典,增加了页面深度的记录

    #为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数
    #现在有了这一功能,我们就有信心爬虫最终一定能够完成。
    #如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等。
    def link_crawler(..., max_depth=2):
        max_depth = 2
        seen = {}
        ...
        depth = seen[url]
        if depth != max_depth:
            for link in links:
                if link not in seen:
                    seen[link] = depth + 1
                    crawl_queue.append(link)
    将上述功能集成到之前的链接爬虫里,有以下代码:

    import urllib.request
    import urllib.error 
    import re #正则表达式
    import urllib.parse #将url链接从相对路径(浏览器可懂但python不懂)转为绝对路径(python也懂了)
    import urllib.robotparser #爬取数据前解析网站robots.txt文件,避免爬取网站所禁止或限制的
    import datetime  #下载限速功能所需模块
    def download(url, user_agent = "brain", proxy = None, num_retries = 2):  #下载url网页,proxy是支持代理功能,初始值为None,想要设置就直接传参数即可
        print("downloading:",url)
        header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6
        req = urllib.request.Request(url, headers = header)    
        
        opener = urllib.request.build_opener()  #为支持代理功能时刻准备着
        if proxy:   #如果设置了proxy,那么就进行以下设置以实现支持代理功能
            proxy_params = { urllib.parse.urlparse(url).scheme: proxy }
            opener.add_handler(urllib.request.ProxyHandler(proxy_params))
            response = opener.open(req)
            
        try:
            html = urllib.request.urlopen(req).read()
        except urllib.error.URLError as e:    #下载过程中出现问题
            print("download error:",e.reason)
            html = None
    
            if num_retries > 0:     #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载
                if hasattr(e, "code") and 500<= e.code <600:
                    return  download(url, user_agent, num_retries-1)  # recursively retry 5XX HTTP errors
        return html
    #download("http://example.webscraping.com") #访问正常
    #download("http://httpstat.us/500") #这个网页测试用,一直是5XXerror
    
    #跟踪链接的爬虫
    #link_crawler()函数传入两个参数:要爬取的网站URL、用于跟踪链接的正则表达式。
    def link_crawler(seed_url, link_regex, max_depth=2):
        """先下载 seed_url 网页的源代码,然后提取出里面所有的链接URL,接着对所有匹配到的链接URL与link_regex 进行匹配,
    如果链接URL里面有link_regex内容,就将这个链接URL放入到队列中,
    下一次 执行 while crawl_queue: 就对这个链接URL 进行同样的操作。
    反反复复,直到 crawl_queue 队列为空,才退出函数。"""
        crawl_queue = [seed_url]
        max_depth = 2 #为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数;如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等
        seen = {seed_url:0} #初始化seed_url访问深度为0
        
        #seen = set(crawl_queue) #有可能链接中互相重复指向,为避免爬取相同的链接,所以我们需要记录哪些链接已经被爬取过(放在集合seen中),若已被爬取过,不再爬取
        while crawl_queue:
            url = crawl_queue.pop()
            
            rp = urllib.robotparser.RobotFileParser()   #爬取前解析网站robots.txt,检查是否可以爬取网站,避免爬取网站禁止或限制的
            rp.set_url("http://example.webscraping.com/robots.txt")
            rp.read()
            user_agent = "brain"
            if rp.can_fetch(user_agent, url):  #解析后发现如果可以正常爬取网站,则继续执行
                
                #爬取网站的下载限速功能的类的调用,每次在download下载前使用
                throttle = Throttle(delay=5) #这里实例网站robots.txt中的delay值为5
                throttle.wait(url)
                html = download(url)   #html = download(url, hearders, proxy=proxy, num_retries=num_retries)这里可以传所需要的参数
                
                html = str(html)
                #filter for links matching our regular expression
                if html == None:
                    continue
    
                depth = seen[url]  #用于避免爬虫陷阱的记录爬取深度的depth
                if depth != max_depth:
                    for link in get_links(html):
                        if re.match(link_regex, link):
                            link = urllib.parse.urljoin(seed_url, link) #把提取的相对url路径link(view/178)转化成绝对路径(/view/Poland-178)link
                            if link not in seen:  #判断是否之前已经爬取
                                seen[link] = depth + 1 #在之前的爬取深度上加1
                                crawl_queue.append(link) #之前没有的话这个链接可用,放在列表中继续进行爬取
            else:
                print("Blocked by %s robots,txt" % url)
                continue
            
    def get_links(html):
        """用来获取一个html网页中所有的链接URL"""
        #做了一个匹配模板 webpage_regex,匹配 <a href="xxx"> or <a href='xxx'>这样的字符串,并提取出里面xxx的URL,请注意这里的xxxURL很可能是源码中相对路径,eg view/1 正常访问肯定是打不开的
        webpage_regex = re.compile('<a href=["\'](.*?)["\']', re.IGNORECASE)
        return re.findall(webpage_regex,html)
        #return re.findall('<a[^>]+href=["\'](.*?)["\']', html)也可以这样实现,但没有上面的先编译模板再匹配好
    
    class Throttle:  #爬取网站的下载限速功能的类的实现,每次在download下载前使用
        """Add a delay between downloads to the same domain"""
        def __init__(self, delay):
            self.delay = delay  # value of delay between downloads for each domain
            self.domains = {}   # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
    
        def wait(self, url):
            domain = urllib.parse.urlparse(url).netloc
            last_accessed = self.domains.get(domain)
    
            if self.delay>0 and last_accessed is not None:
                sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).seconds
                if sleep_secs > 0:
                    time.sleep(sleep_secs)  #domain has been accessed recently,so need to sleep
            self.domains[domain] = datetime.datetime.now()
    
    #只想找http://example.webscraping.com/index... or http://example.webscraping.com/view...
    link_crawler("http://example.webscraping.com", "/(index|view)")
    展开全文
  • 基于历史数据查询的爬虫操作

    千次阅读 2016-07-03 13:26:45
    历史查询需要通过网页中的日历控件选择,而且日历控件只有在点击日期之后才会生效,也就是说,要查询2016年7月3日12:00的数据,需要先点击日历,然后通过小时和分钟的加减获得12:00,再选择年、月和日。这样的操作能...

    网站:http://www.szmb.gov.cn/article/QiXiangJianCe/

    目的:抓取过去一年内深圳各个区的逐小时降雨数据

    历史查询需要通过网页中的日历控件选择,而且日历控件只有在点击日期之后才会生效,也就是说,要查询2016年7月3日12:00的数据,需要先点击日历,然后通过小时和分钟的加减获得12:00,再选择年、月和日。这样的操作能通过selenium实现,困难在于,该网站设置该日历控件的输入值type=“hidden”,且设置日期的属性unselectable=“on”,display=“none”。也就是说,无法通过selenium实现模拟人的点击操作。因此尝试以下方法:

    1.设置该input的type为text型,而不是hidden类型。再通过selenium的send_keys方法输入新的日期值,并submit。结果:失败。原因:设置input的value并没有用,因为input的value值是通过其他方式赋值的,不会对查询操作有任何影响。

    2.模拟点击操作。如上所述,失败。

    以上两种方法折磨了我一晚上+一上午。

    3.人工点击,并监听浏览器的get和post行为。果然,发现在控制台出现如下操作:


    数据通过text/html传送,果不其然,js代码对数据的操作必须要有某种数据流实现与服务器之间的数据传递。点击日历的2016年5月5日15:00时,则试图返回的网页为:

    http://www.szmb.gov.cn/data_center/?controller=shenzhenweather&action=hismonitor&json=1&date=2016-05-05%2015:00
    分析其结构组成发现其功能为查询深圳的监测站历史天气数据,返回格式为json,日期为2016-05-05%2015:00,%20显然代表空格。通过修改json=?后的值发现,当其为1时,返回的为json格式,当json=0时,返回的为标准的xml格式,这富裕数据查询十分方便。发现新大陆!
    # coding=utf-8
    # Created on 3 Jul, 2016
    # Author: Liuph
    # Version:1.0
    import urllib
    import urllib2
    import re
    import time
    import os
    import string
    
    #下载html
    def getHtml(url):
        user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        headers = {'User-Agent': user_agent}
        req = urllib2.Request(url, headers=headers)
        html = urllib2.urlopen(req).read()
        return html
    
    
    #解析html
    def getElement(html):
        #日期时间
        reg_date= r'(?<=\<date\>)(.+?)(?=\</date\>)'
        #行政区
        reg_area = r'area="(.+?)"'
        #站点名称
        reg_obt = r'obt="(.+?)"'
        #小时降雨
        reg_rain = r'(?<=\<rh\>)(.+?)(?=\</rh\>)'
        #24小时降雨
        reg_rain24 = r'(?<=\<r24h\>)(.+?)(?=\</r24h\>)'
    
        re_date = re.compile(reg_date)
        re_area = re.compile(reg_area)
        re_obt = re.compile(reg_obt)
        re_rain = re.compile(reg_rain)
        re_rain24 = re.compile(reg_rain24)
    
        elems_date = re.findall(re_date, html)
        elems_area = re.findall(re_area, html)
        elems_obt = re.findall(re_obt, html)
        elems_rain = re.findall(re_rain, html)
        elems_rain24 = re.findall(re_rain24, html)
        if (len(elems_date) > 0):
            output_file = open("his/" + str(elems_date[0])[0:13] + ".txt", 'w')
            output_file.write(elems_date[0] + "\n")
            for i in range(len(elems_obt)):
                output_file.write(elems_area[i] + "," + elems_obt[i] + "," + elems_rain[i] + "," + elems_rain24[i] + "\n")
            output_file.close()
    
    
    Months = ['2015-07','2015-08','2015-09','2015-10','2015-11','2015-12','2016-01','2016-02','2016-03','2016-04','2016-05','2016-06','2016-07']
    MaxDays = [31,31,30,31,30,31,31,28,31,30,31,30,3]
    Hours = ['00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23']
    
    
    for i in range(0,13):
        _month = Months[i]
        for _day in range(1,32):
            if _day > MaxDays[i]:
                continue
            if _day < 10:
                _day = '0'+str(_day)
            else:
                _day = str(_day)
            for _hour in Hours:
                DDateTime = _month + "-" + _day + '%20' + _hour +':00'
                #时间:从2015年7月1日至2016年7月3日
                url = 'http://www.szmb.gov.cn/data_center/?controller=shenzhenweather&action=hismonitor&json=0&date='+DDateTime
                print url
                html = getHtml(url)
                getElement(html)
                #exit()
    

    于是启动全程连接,开始开心地抓数据了!
    
    
    
    
    附上对实时抓取代码的更新(因为实时数据的一小时数据为当前小时的累积数据,所以设置每个小时的58~59分钟抓取最能满足1小时条件)
    # coding=utf-8
    from testString import *
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    import string
    import os
    
    import time
    
    
    
    district_navs = ['nav2','nav1','nav3','nav4','nav5','nav6','nav7','nav8','nav9','nav10']
    district_names = ['福田区','罗湖区','南山区','盐田区','宝安区','龙岗区','光明新区','坪山新区','龙华新区','大鹏新区']
    strTime = str(time.strftime("%Y%m%d%H%M", time.localtime(time.time())))
    
    flag = 1
    while (flag == 1):
        if (strTime[-2:] == '58'):
            driver = webdriver.Chrome()
            driver.get("http://www.szmb.gov.cn/article/QiXiangJianCe/")
            # 选择降雨量
            driver.find_element_by_xpath("//span[@id='fenqu_H24R']").click()
    
            filename = "data/"+strTime + '.txt'
            #创建文件
            output_file = open(filename, 'w')
            # 选择行政区
            for i in range(len(district_navs)):
                driver.find_element_by_xpath("//div[@id='" + district_navs[i] + "']").click()
                # print driver.page_source
                timeElem = driver.find_element_by_id("time_shikuang")
                #输出时间和站点名
                output_file.write(timeElem.text + ',')
                output_file.write(district_names[i] + ',')
                elems = driver.find_elements_by_xpath("//span[@οnmοuseοver='javscript:changeTextOver(this)']")
                #输出每个站点的数据,格式为:站点名,一小时降雨量,当日累积降雨量
                for elem in elems:
                    output_file.write(AMonitorRecord(elem.get_attribute("title")) + ',')
                output_file.write('\n')
            output_file.close()
            driver.close()
    
        time.sleep(60)
        strTime = str(time.strftime("%Y%m%d%H%M", time.localtime(time.time())))
    
    
    
    
    


    展开全文
  • // 统一设置日历格式 Calendar calendar = Calendar.getInstance(); calendar.s ...ionic中input框禁止输入问题其实这个问题在之后沥青思路之后觉得还是挺好实现的,没有思路的时候真是找不到头绪~ 功能的描述为:当...
  • ps: 主要是熟悉pyqt5, 加入了单选框 输入框 文本框 文件夹选择框及日历下拉框 效果图: pyqt5 主程序文件 # -*- coding: utf-8 -*- # @Author: Mehaei # @Date: 2019-07-10 13:02:56 # @Last ...
  • /1 前言/搜狗壁纸是一款高清电脑壁纸下载,集成万款美女、宠物、风景、电影、节日、日历、简约壁纸,一键更换壁纸,多分辨率自适应,支持分组播放。搜狗壁纸,素材丰富,种类齐全...
  • 在 牛客网--求职--笔试日历 可以笔试时间每天都有哪些公司有笔试,如下图 一、需求 1、看看这个有笔试的公司哪家你还没看过。 2、看看自己投过的公司哪家这个月有笔试及笔试的时间。 当然,你还是得把你投...
  • python datetime 获取日历时间

    千次阅读 2019-08-08 11:43:39
    如题 用处: 1.操作爬虫时间 2.处理数据 代码: from datetime import datetime, timedelta def obtain_time(): ...
  • 王思聪又又又上了微博热搜——然而这次却不是关于娱乐圈。 最近几天,王思聪与他的“限消令”接连登上热搜榜,引发吃瓜群众们广泛热议。...利用pyecharts生成思聪在2017年上热搜的日历热度...
  • 由于学校没有课表接口,不能使用超级课程表之类的课表软件,并且手上有块apple watch,便想将课表信息导入到日历中,每天就可以优雅的看到课程信息了。 ok,本教程需要一定的爬虫基础,因为各个学校的教务网站不同,...
  • 欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!...作者:法纳斯特,Python爱好者,专注爬虫,数据分析及可视化微信公众号:法...
  • 知识有价 公众号从5月31号开始第一次发文,到现在快一个月了。27天的时间里,更新了26篇文章。因为感觉每天更新身体有些扛不住,所以从上周开始,每周五给自己放个假,找...之前写的flask制作美观的网页日历,获得了...
  • 对于爬虫爬取数据,你的第一印象是什么?Python 脚本?还是Scrapy、WebMagic、Crawler4j(Java),这样的大型框架。一般这样的编程去爬取数据可能需要 一两个小时或者一两天不等的时间。而且这里还有一些技术门槛,...
  • 作者丨kingname来源丨本文授权转载自未闻Code(ID:itskingname)开发爬虫的同学肯定用过 Chrome 开发者工具自动定位页面元素对应的 HTML 标签的功能,如下图所示:那么有没有同学思考过,这个功能,如果用 JavaScript...
  • 爬虫编写ics文件生成生成ics日历订阅爬虫定期爬取数据最终效果示例 ????分析与结论 ????帮助链接 摘要 ???? 知识准备 RFC 2445标准:1998由微软公司发布的标准的互联网日历标准,让用户能够在各种计算
  • 小孩日历 孩子的日历 实验室标签 网站Internet sof Symfony 搬运工 Gestion de docker avec portainer 回购 检查我的回购github 即时通讯 差遣使者改组消息 曲菲克 Docker de configuration pour lancer TRAEFIK ...
  • Python 基础笔记

    2021-03-16 09:50:20
    Python 基础笔记内置函数print() 打印输出type() 数据类型...获取当前时间获取格式化的时间格式化日期获取某月日历Calendar(日历模块)math(数学函数)math.ceil() 向上取数requests 爬虫JSONBeautifulSoup引号的用
  • RT:记录工作中客户提出的新需求,分辨日期是否是节假日与工作日,主要实现过程比较简单,通过爬虫获取百度日历数据接口,具体接口地址在下方代码中已经写明,调用接口判断日期即可,其中第一个参数为年份,第二个...
  • 一、背景因业务需要获取风险经济事件并采取应对措施,但因为种种原因又疏忽于每天去查看财经日历,于是通过爬取金十数据网站并自动推送到微信查看。二、目标实现image三、环境与工具1、pycharm:python开发IDE四、...
  • Atiti attilax主要成果与解决方案与案例rsm版       1. ##----------主要成果与解决方案与 参与项目 1 ...###文字文本处理 自然语言处理 日历处理系列 结构化查询 大数据查询系列 au 2 ##
  • 前言:某天突发奇想,想要实现一个农历生日提醒。这个时候有了如下的大概思路:获取农历 ——>匹配——>提醒发现实现这个需求最主要的在...思考了许久,想到可以通过爬虫爬取现成的日历信息,存库再进行匹配...
  • 调度器Quartz的简述与使用总结

    千次阅读 2017-07-27 20:29:47
    比如对特定类型新闻或股指期货指数等内容的爬取,可以编写爬虫程序然后使用Quartz在后台指定特定时间点对任务进行执行,来自动收集信息。大型系统间数据的按时批量导入任务也可由Quartz进行调度。Quartz提供两种类型...
  • 之前一直用爬虫捉取路由实时上下载的记录用数据库保存,有时可用matplotlib来查看时间与上下传的曲线图,但是静态的,查询的时间段需自行认定,虽然qt的日历类可以比较方便取日期按日期查,但总觉要点有点麻烦,又不...
  • 之前一直用爬虫捉取路由实时上下载的记录用数据库保存,有时可用matplotlib来查看时间与上下传的曲线图,但是静态的,查询的时间段需自行认定,虽然qt的日历类可以比较方便取日期按日期查,但总觉要点有点麻烦,又不...

空空如也

空空如也

1 2 3
收藏数 60
精华内容 24
关键字:

日历爬虫

爬虫 订阅