精华内容
参与话题
问答
  • 爬虫入门

    千次阅读 2017-11-13 17:19:12
    爬虫入门 1. 概述 本文首先介绍Requests库如何自动爬取HTML页面以及如何自动网络请求提交,随后将会讲解如何阅读网络爬虫排除标准。获取了网页之后用BeautifulSoup库解析HTML页面,然后讲解正则表达式,以及如何用...

    爬虫入门

    1.   概述

    本文首先介绍Requests库如何自动爬取HTML页面以及如何自动网络请求提交,随后将会讲解如何阅读网络爬虫排除标准。获取了网页之后用BeautifulSoup库解析HTML页面,然后讲解正则表达式,以及如何用正则表达式提取网页关键信息。当然会有很多实战内容如下:

    • 京东商品页面的爬取
    • 亚马逊商品页面的爬取
    • 百度/360搜索关键字提交
    • 网络图片的爬取和存储
    • IP地址归属地的自动查询



    2.  Requests库介绍

    2.1.Requests库主要有7个主要方法:

    (1)requests.request() 构造一个请求,支撑以下各方法的基础方法

    (2)requests.get() 获取HTML网页的主要方法,对应于HTTP的GET

    GET请求获取URL位置的资源


    requests.get(url, params=None, **kwargs)

    ∙ url : 拟获取页面的url链接

    ∙ params :url中的额外参数,字典或字节流格式,可选

    ∙ **kwargs:12个控制访问的参数

    (3)requests.head() 获取HTML网页头信息的方法,对应于HTTP的HEAD

        HEAD请求获取URL位置资源的响应消息报告,即获得该资源的头部信息

    requests.head(url, **kwargs)

    (4)requests.post()向HTML网页提交POST请求的方法,对应于HTTP的        POST. POST 请求向URL位置的资源后附加新的数据

    requests.post(url, data=None,json=None,**kwargs)

    (5)requests.put() 向HTML网页提交PUT请求的方法,对应于HTTP的PUT

      PUT 请求向URL位置存储一个资源,覆盖原URL位置的资源

    requests.put(url, data=None,**kwargs)

    (6)requests.patch() 向HTML网页提交局部修改请求,对应于HTTP的        PATCH。PATCH 请求局部更新URL位置的资源,即改变该处资源的部分内容

    requests.patch(url, data=None,**kwargs)

    (7)requests.delete() 向HTML页面提交删除请求,对应于HTTP的DELETE

    DELETE 请求删除URL位置存储的资源

    requests.delete(url, **kwargs)




    2.2.Requests库的13个访问参数

    (1)params : 字典或字节序列,作为参数增加到url中

    >>> kv = {'key1': 'value1','key2':'value2'}
    >>> r = requests.request('GET', 'http://python123.io/ws',params=kv)
    >>> print(r.url)
    http://python123.io/ws?key1=value1&key2=value2

    (2)data : 字典、字节序列或文件对象,作为Request的内容

    >>> kv = {'key1': 'value1', 'key2':'value2'}
    >>> r = requests.request('POST', 'http://python123.io/ws',data=kv)
    >>> body = '主体内容'
    >>> r = requests.request('POST', 'http://python123.io/ws',data=body)

    (3)json : JSON格式的数据,作为Request的内容

    >>> kv = {'key1': 'value1'}
    >>> r = requests.request('POST', 'http://python123.io/ws',json=kv)

    (4)headers : 字典,HTTP定制头

    >>> hd = {'user‐agent': 'Chrome/10'}
    >>> r = requests.request('POST', 'http://python123.io/ws',headers=hd)

    (5)cookies : 字典或CookieJar,Request中的cookie

    (6)auth : 元组,支持HTTP认证功能

    (7)files : 字典类型,传输文件

    >>> fs = {'file': open('data.xls', 'rb')}
    >>> r = requests.request('POST', 'http://python123.io/ws', files=fs)

    (8)timeout : 设定超时时间,秒为单位

    >>> r = requests.request('GET', 'http://www.baidu.com',timeout=10)

    (9)proxies : 字典类型,设定访问代理服务器,可以增加登录认证

    >>> pxs = { 'http': 'http://user:pass@10.10.10.1:1234'
    'https': 'https://10.10.10.1:4321' }
    >>> r = requests.request('GET', 'http://www.baidu.com', proxies=pxs)

    (10)allow_redirects : True/False,默认为True,重定向开关

    (11)stream : True/False,默认为True,获取内容立即下载开关

    (12)verify : True/False,默认为True,认证SSL证书开关

    (13)cert : 本地SSL证书路径

    2.3.Response对象的属性

    (1)r.status_code HTTP请求的返回状态,200表示连接成功404表示失败
    (2)r.text HTTP响应内容的字符串形式,即,url对应的页面内容
    (3)r.encoding 从HTTP header中猜测的响应内容编码方式
    (4)r.apparent_encoding 从内容中分析出的响应内容编码方式
    (5)r.content HTTP响应内容的二进制形式

    注意:r.encoding:如果header中不存在charset认为编码为ISO‐8859-1

          r.text根据r.encoding显示网页内容

    r.apparent_encoding:根据网页内容分析出的编码方式,可以看作是r.encoding的备选

     

    2.4.Requests库的异常

    r.raise_for_status()在方法内部判断r.status_code是否等于200,不需要增加额外的if语句,该语句便于利用try‐except进行异常处理



    2.5.爬取网页的通用代码框架

    importrequests
    def getHtml(url):
       
    try:
            r = requests.get(url
    ,timeout=30)
            r.raise_for_status()
            r.encoding=r.apparent_encoding
           
    return r.text
       
    except:
           
    return  "error"
    url="http://www.baidu.com"
    print(getHtml(url))



    3.  Robots协议的使用

    3.1网络爬虫引发的的问题

    (1)Web服务器默认接收人类访问受限于编写水平和目的,网络爬虫将会为Web服务器带来巨大的资源开销

    (2)服务器上的数据有产权归属网络爬虫获取数据后牟利将带来法律风险

    (3)网络爬虫可能具备突破简单访问控制的能力,获得被保护数据

    从而泄露个人隐私

    3.2网络爬虫的限制

    (1)来源审查:判断User‐Agent进行限制

    检查来访HTTP协议头的User‐Agent域,只响应浏览器或友好爬虫的访问

    (2)发布公告:Robots协议

    告知所有爬虫网站的爬取策略,要求爬虫遵守

    3.3.Robots协议

    RobotsExclusion Standard,网络爬虫排除标准
    (1)作用:网站告知网络爬虫哪些页面可以抓取,哪些不行
    (2)形式:在网站根目录下的robots.txt文件

    (3)网络爬虫:自动或人工识别robots.txt,再进行内容爬取
    (4)约束性:Robots协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险


    4.  Requests库网络爬取实战

    实例1:京东商品页面的爬取

    (1)商品网址https://item.jd.com/2967929.html


    (2)代码实例及结果

    import requests
    def getHtml(url):
        try:
            r = requests.get(url,timeout=30)
            r.raise_for_status()
            r.encoding=r.apparent_encoding
            return r.text
        except:
            return  "error"
    url="https://item.jd.com/2967929.html"
    print(getHtml(url))

     

    实例2:亚马逊商品页面的爬取

    (1)商品网址https://www.amazon.cn/gp/product/B01M8L5Z3Y




    这里出现错误主要原因是亚马逊网站识别出了这是爬虫去获取网页信息,这里解决方案是采取伪装成浏览器的方式去访问

    (2)实例代码

    import requests
    url="https://www.amazon.cn/gp/product/B01M8L5Z3Y"
    try:
        kv = {'user-agent':'Mozilla/5.0'}
        r=requests.get(url,headers=kv)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(r.text[:1000])
    except:
        print("爬取失败")

    实例3:百度/360搜索关键词提交

    (1)  百度的关键词接口:http://www.baidu.com/s?wd=keyword

    (2)  360的关键词接口:http://www.so.com/s?q=keyword

    (3)  百度的关键词接口实例代码

    import requests
    url="http://www.baidu.com/s"
    keyword="Java"
    try:
        kv = {'wd':keyword}
        r=requests.get(url,params=kv)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(len(r.text))
    except:
        print("爬取失败")

    (4)  360的关键词接口实例代码

    import requests
    url="http://www.so.com/s"
    keyword="Java"
    try:
        kv = {'q':keyword}
        r=requests.get(url,params=kv)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(len(r.text))
    except:
        print("爬取失败")

    实例4:网络图片的爬取和存储

    (1)图片地址:

    http://image.nationalgeographic.com.cn/2014/0707/20140707104220398.jpg

    (2)图片爬取全代码:

    import requests
    import os
    url="http://image.nationalgeographic.com.cn/2014/0707/20140707104220398.jpg"
    root="E://pics//"
    path=root+url.split('/')[-1]
    try:
        if not os.path.exists(root):
            os.mkdir(root)
        if not os.path.exists(path):
            r=requests.get(url)
            with open(path,'wb') as f:
                f.write(r.content)
                f.close()
                print("文件保存成功")
        else:
            print("文件已存在")
    except:
        print("爬虫失败")


    实例5:IP地址归属地的自动查询

    (1)  网页地址:http://m.ip138.com/ip.asp?ip=ipaddress

    (2)  代码实例:

    import requests
    url="http://m.ip138.com/ip.asp?ip="
    try:
        r=requests.get(url+'202.204.80.112')
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(r.text[-500:])
    except:
        print("爬取失败")

     

    5.Beautiful Soup库入门

    5 .1 Beautiful Soup库小案例

    (1)  页面网址:http://python123.io/ws/demo.html

    (2)  实例代码:

    import requests
    from bs4 import BeautifulSoup
    r=requests.get("http://python123.io/ws/demo.html")
    demo=r.text
    soup=BeautifulSoup(demo,'html.parser')
    print(soup.prettify())

     

    (3)  解析结果:

    5 .2 Beautiful Soup库的理解




    5 .3 Beautiful Soup库的引用

    (1)Beautiful Soup库,也叫beautifulsoup4 或 bs4

    (2)约定引用方式如下,即主要是用BeautifulSoup类

    from bs4 import BeautifulSoup
    import bs4

    5 .4BeautifulSoup类

    (1)Tag 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾

    (任何存在于HTML语法中的标签都可以用soup.<tag>访问获得,当HTML文    档中存在多个相同<tag>对应内容时,soup.<tag>返回第一个)

    (2)Name 标签的名字,<p>…</p>的名字是'p',格式:<tag>.name

    (3)Attributes 标签的属性,字典形式组织,格式:<tag>.attrs

    (4)NavigableString 标签内非属性字符串,<>…</>中字符串,格式:<tag>.string

    (5)Comment 标签内字符串的注释部分,一种特殊的Comment类型

    (6)举例说明:

    import requests
    from bs4 import BeautifulSoup
    import bs4
    r=requests.get("http://python123.io/ws/demo.html")
    demo=r.text
    soup=BeautifulSoup(demo,'html.parser')
    print(soup.title)
    tag=soup.a
    print(tag)
    print(tag.name)
    print(tag.parent.name)
    print(tag.attrs['class'])
    print(type(tag))
    print(tag.string)

    输出结果:

    a

    p

    ['py1']

    <class'bs4.element.Tag'>

    BasicPython

    5 .5基于bs4库的HTML内容遍历方法

    (1)HTML基本格式


    (2)标签树的下行遍历

    .contents子节点的列表,将<tag>所有儿子节点存入列表
    .children 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
    .descendants 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
    BeautifulSoup类型是标签树的根节点

    举例说明:

    print(soup.head)
    print(soup.head.contents)

    <head><title>Thisis a python demo page</title></head>

    [<title>Thisis a python demo page</title>]

    遍历方法:

    forchild in soup.body.children:
    print(child)
    for child in soup.body.descendants:
    print(child)

    (3)标签树的上行遍历

    .parent节点的父亲标签
    .parents 节点先辈标签的迭代类型,用于循环遍历先辈节点

    遍历所有先辈节点,包括soup本身,所以要区别判断

    使用实例:

    for parent in soup.a.parents:
        if parent is None:
            print(parent)
        else:
            print(parent.name)

    p

    body

    html

    [document]

    (4)标签树的平行遍历、

    .next_sibling返回按照HTML文本顺序的下一个平行节点标签

    .previous_sibling返回按照HTML文本顺序的上一个平行节点标签

    .next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签

    .previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

    5.6 基于bs4库的HTML格式输出

    (1) bs4库的prettify()方法

    .prettify()为HTML文本<>及其内容增加更加'\n'

    .prettify()可用于标签,方法:<tag>.prettify()

    (2)  bs4库的编码

    bs4库将任何HTML输入都变成utf‐8编码

    Python3.x默认支持编码是utf‐8,解析无障碍




    6.  信息标记与提取方法

    6.1 信息的标记

    标记后的信息可形成信息组织结构,增加了信息维度

    标记的结构与信息一样具有重要价值

    标记后的信息可用于通信、存储或展示

    标记后的信息更利于程序理解和运用

    6.2 HTML的信息标记

     

    6.3 XML信息标记


    6.4 信息提取的一般方法

    方法一:完整解析信息的标记形式,再提取关键信息
    需要标记解析器,例如:bs4库的标签树遍历
    优点:信息解析准确
    缺点:提取过程繁琐,速度慢

    方法二:无视标记形式,直接搜索关键信息

    对信息的文本查找函数即可

    优点:提取过程简洁,速度较快

    缺点:提取结果准确性与信息内容相关

    方法三:结合形式解析与搜索方法,提取关键信息

    实例:提取HTML中所有URL链接

    思路:1) 搜索到所有<a>标签

    2) 解析<a>标签格式,提取href后的链接内容

    r=requests.get("http://python123.io/ws/demo.html")
    demo=r.text
    soup=BeautifulSoup(demo,'html.parser')
    for link  in soup.find_all('a'):
        print(link.get('href'))
     

    6.5基于bs4库的HTML内容查找方法

    (1)<>.find_all(name,attrs, recursive, string, **kwargs)方法

    返回一个列表类型,存储查找的结果

    <1>∙ name : 对标签名称的检索字符串

    print(soup.find_all('a'))

    [<a class="py1" href="http://www.icourse163.org/course/BIT-268001"id="link1">BasicPython</a>, <a class="py2"href="http://www.icourse163.org/course/BIT-1001870001"id="link2">Advanced Python</a>]

    for tag in soup.find_all(True):
        print(tag.name)

    html

    head

    title

    body

    p

    b

    p

    a

    a

    for tag in soup.find_all(re.compile('b')):
        print(tag.name)

    body

    b

    <2>  attrs:对标签属性值的检索字符串,可标注属性检索

    import  re
    print(soup.find_all(id=re.compile('link')))

    <3> recursive: 是否对子孙全部检索,默认True

    <4> string: <>…</>中字符串区域的检索字符串

    import  re
    print(soup.find_all(string=re.compile('python')))

    ['This is a python demo page', 'The demo python introducesseveral python courses.']

    (2) <tag>(..) 等价于 <tag>.find_all(..)

    soup(..) 等价于 soup.find_all(..)

     

    (3)扩展方法

    <>.find() 搜索且只返回一个结果,同.find_all()参数

    <>.find_parents() 在先辈节点中搜索,返回列表类型,同.find_all()参数

    <>.find_parent() 在先辈节点中返回一个结果,同.find()参数

    <>.find_next_siblings() 在后续平行节点中搜索,返回列表类型,同.find_all()参数

    <>.find_next_sibling() 在后续平行节点中返回一个结果,同.find()参数

    <>.find_previous_siblings() 在前序平行节点中搜索,返回列表类型,同.find_all()参数

    <>.find_previous_sibling() 在前序平行节点中返回一个结果,同.find()参数


    7.  正则表达式入门

    7.1 正则表达式的概念

    正则表达式是用来简洁表达一组字符串的表达式,是一种通用的字符串表达框架,是一种针对字符串表达“简洁” 和“特征” 思想的工具,可以用来判断某字符串的特征归属。

    可以用于表达文本类型的特征(病毒、入侵等),同时查找或替换一组字符串,匹配字符串的全部或部分

    7.2 正则表达式的常用操作符

    . ; 表示任何单个字符

    [ ]; 字符集,对单个字符给出取值范围;[abc] 表示a、 b、 c,[a‐z]表示a到z单个字符

    [^ ] ;非字符集,对单个字符给出排除范围 [^abc];表示非a或b或c的单个字符

    *; 前一个字符0次或无限次扩展 abc* ;表示 ab、 abc、 abcc、 abccc等

    +; 前一个字符1次或无限次扩展 abc+ ;表示abc、 abcc、 abccc等

    ? ;前一个字符0次或1次扩展 abc? ;表示 ab、 abc

    | ;左右表达式任意一个 abc|def ;表示 abc、def

    {m} ;扩展前一个字符m次 ;ab{2}c表示abbc

    {m,n} ;扩展前一个字符m至n次(含n); ab{1,2}c表示abc、 abbc

    ^ ;匹配字符串开头 ;^abc表示abc且在一个字符串的开头

    $ ;匹配字符串结尾 ;abc$表示abc且在一个字符串的结尾

    ( ); 分组标记,内部只能使用 | 操作符; (abc)表示abc,(abc|def)表示abc、 def

    \d ;数字,等价于[0‐9]

    \w ;单词字符,等价于[A‐Za‐z0‐9_]

     

    例子:

    P(Y|YT|YTH|YTHO)?N  'PN'、 'PYN'、 'PYTN'、'PYTHN'、 'PYTHON'

    PYTHON+                   'PYTHON'、 'PYTHONN'、 'PYTHONNN' …

    PY[TH]ON                    'PYTON'、 'PYHON'

    PY[^TH]?ON                'PYON'、 'PYaON'、 'PYbON'、 'PYcON'…

    PY{:3}N                        'PN'、 'PYN'、 'PYYN'、 'PYYYN'

    ^[A‐Za‐z]+$          由26个字母组成的字符串

    ^[A‐Za‐z0‐9]+$         由26个字母和数字组成的字符串

    ^‐?\d+$                      整数形式的字符串

    ^[0‐9]*[1‐9][0‐9]*$    正整数形式的字符串

    [1‐9]\d{5}                 中国境内邮政编码,6位

    [\u4e00‐\u9fa5]       匹配中文字符

    \d{3}‐\d{8}|\d{4}‐\d{7} 国内电话号码,010‐68913536

    (([1‐9]?\d|1\d{2}|2[0‐4]\d|25[0‐5]).){3}([1‐9]?\d|1\d{2}|2[0‐4]\d|25[0‐5])  

    IP地址字符串形式的正则表达式(IP地址分4段,每段0‐255)

    7.3 Python Re库的使用方式

    (1)Re库一些基本知识

    Re库是Python的标准库,主要用于字符串匹配

    re库采用raw string类型表示正则表达式,表示为:r'text'

    例如: r'[1‐9]\d{5}'    r'\d{3}‐\d{8}|\d{4}‐\d{7}'

    raw string是不包含对转义符再次转义的字符串

    re库也可以采用string类型表示正则表达式,但更繁琐

    例如:'[1‐9]\\d{5}'     '\\d{3}‐\\d{8}|\\d{4}‐\\d{7}'

    建议:当正则表达式包含转义符时,使用raw string

    (2)Re库的主要功能函数

    re.search() 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象

    re.search(pattern, string, flags=0)

    pattern :正则表达式的字符串或原生字符串表示

    string :待匹配字符串

    flags :正则表达式使用时的控制标记

    import re
    match =re.search(r'[1-9]\d{5}','BIT 100081')
    if match:
        print(match.group(0))

    结果:100081

    re.match() 从一个字符串的开始位置起匹配正则表达式,返回match对象

    import re
    match =re.match(r'[1-9]\d{5}','100081 BIT')
    if match:
        print(match.group(0))

    结果:100081

    re.findall() 搜索字符串,以列表类型返回全部能匹配的子串

    import re
    ls =re.findall(r'[1-9]\d{5}','100081 BIT  100011 BIT')
    print(ls)

    结果:['100081', '100011']

    re.split() 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型

    import re
    print(re.split(r'[1-9]\d{5}','100081 BIT  100011 BIT'))

    结果:['', ' BIT  ', ' BIT']

    re.finditer() 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对

    import re
    for m in re.finditer(r'[1-9]\d{5}','BIT100081  BIT100081'):
        if m:
            print(m.group(0))

    结果:100081

    100081

    re.sub() 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

    re.sub(pattern, repl, string, count=0, flags=0)

    pattern :正则表达式的字符串或原生字符串表示

    repl :替换匹配字符串的字符串

    string :待匹配字符串

    count :匹配的最大替换次数

    flags :正则表达式使用时的控制标记

    import re
    print(re.sub(r'[1-9]\d{5}','zipcode','BIT100081  BIT100081'))

    结果:BITzipcode  BITzipcode

     

    regex =re.compile(pattern, flags=0)

    ∙ pattern : 正则表达式的字符串或原生字符串表示

    ∙ flags : 正则表达式使用时的控制标记

    >>> regex =re.compile(r'[1‐9]\d{5}')

    然后regex对象有六种方法,与上面函数功能相同

     

    将正则表达式的字符串形式编译成正则表达式对

    常用标记              说明

    re.I re.IGNORECASE  忽略正则表达式的大小写,[A‐Z]能够匹配小写字符

    re.M re.MULTILINE  正则表达式中的^操作符能够将给定字符串的每行当作匹配开

                       始

    re.S re.DOTALL      正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外           的所有字符

    (4)  Re库的match对象

    Match对象是一次匹配的结果,包含匹配的很多信息

    属性         说明  

    .string        待匹配的文本

    .re              匹配时使用的patter对象(正则表达式)

    .pos           正则表达式搜索文本的开始位置

    .endpos     正则表达式搜索文本的结束位置

     

    方法         说明

    .group(0)   获得匹配后的字符串

    .start()       匹配字符串在原始字符串的开始位置

    .end()         匹配字符串在原始字符串的结束位置

    .span()       返回(.start(),.end())

    (5)  Re库的匹配方式

    默认采取最大匹配,只要长度输出可能不同的,都可以通过在操作符后增加?变成最小匹配

    操作符         说明

    *?               前一个字符0次或无限次扩展,最小匹配

    +?              前一个字符1次或无限次扩展,最小匹配

    ??               前一个字符0次或1次扩展,最小匹配

    {m,n}?        扩展前一个字符m至n次(含n),最小匹配

    展开全文
  • Python爬虫入门项目

    万次阅读 多人点赞 2017-12-25 16:26:21
    Python是什么 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。 创始人Guido van Rossum是BBC出品英剧Monty Python’s Flying Circus(中文:蒙提·派森的...

    Python是什么

    Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。

    创始人Guido van Rossum是BBC出品英剧Monty Python’s Flying Circus(中文:蒙提·派森的飞行马戏团)的狂热粉丝,因而将自己创造的这门编程语言命名为Python。

    人生苦短,我用python,翻译自"Life is short, you need Python"

    Python英式发音:/ˈpaɪθən/ ,中文类似‘拍森’。而美式发音:/ˈpaɪθɑːn/,中文类似‘拍赏’。我看麻省理工授课教授读的是‘拍赏’,我觉得国内大多是读‘拍森’吧。

    2017年python排第一也无可争议,比较AI第一语言,在当下人工智能大数据大火的情况下,python无愧第一语言的称号,至于C、C++、java都是万年的老大哥了,在代码量比较方面,小编相信java肯定是完爆其它语言的。

    不过从这一年的编程语言流行趋势看,java依然是传播最多的,比较无论app、web、云计算都离不开,而其相对python而言,学习路径更困难一点,想要转行编程,而且追赶潮流,python已然是最佳语言。

    许多大型网站就是用Python开发的,国内:豆瓣、搜狐、金山、腾讯、盛大、网易、百度、阿里、淘宝、热酷、土豆、新浪、果壳…; 国外:谷歌、NASA、YouTube、Facebook、工业光魔、红帽…

    Python将被纳入高考内容

    浙江省信息技术课程改革方案已经出台,Python确定进入浙江省信息技术高考,从2018年起浙江省信息技术教材编程语言将会从vb更换为Python。其实不止浙江,教育大省北京和山东也确定要把Python编程基础纳入信息技术课程和高考的内容体系,Python语言课程化也将成为孩子学习的一种趋势。尤其山东省最新出版的小学信息技术六年级教材也加入了Python内容,小学生都开始接触Python语言了!!

    再不学习,又要被小学生完爆了。。。

     

    Python入门教程

    Python能做什么

    • 网络爬虫
    • Web应用开发
    • 系统网络运维
    • 科学与数字计算
    • 图形界面开发
    • 网络编程
    • 自然语言处理(NLP)
    • 人工智能
    • 区块链
    • 多不胜举。。。

    Python入门爬虫

    这是我的第一个python项目,在这里与大家分享出来~

    • 需求
      • 我们目前正在开发一款产品其功能大致是:用户收到短信如:购买了电影票或者火车票机票之类的事件。然后app读取短信,解析短信,获取时间地点,然后后台自动建立一个备忘录,在事件开始前1小时提醒用户。
    • 设计
      • 开始我们将解析的功能放在了服务端,但是后来考虑到用户隐私问题。后来将解析功能放到了app端,服务端只负责收集数据,然后将新数据发送给app端。
      • 关于服务端主要是分离出两个功能,一、响应app端请求返回数据。二、爬取数据,存入数据库。
      • 响应请求返回数据使用java来做,而爬取数据存入数据库使用python来做,这样分别使用不同语言来做是因为这两种语言各有优势,java效率比python高些,适合做web端,而爬取数据并不是太追求性能且python语言和大量的库适合做爬虫。
    • 代码
      • 本项目使用python3的版本
      • 获取源码:扫描下方关注微信公众号「裸睡的猪」回复:爬虫入门 获取
         

         

      • 了解这个项目你只需要有简单的python基础,能了解python语法就可以。其实我自己也是python没学完,然后就开始写,遇到问题就百度,边做边学这样才不至于很枯燥,因为python可以做一些很有意思的事情,比如模拟连续登录挣积分,比如我最近在写一个预定模范出行车子的python脚本。推荐看廖雪峰的python入门教程
      • 首先带大家看看我的目录结构,开始我打算是定义一个非常好非常全的规范,后来才发现由于自己不熟悉框架,而是刚入门级别,所以就放弃了。从简而入:
      • 下面咱们按照上图中的顺序,从上往下一个一个文件的讲解init.py包的标识文件,python包就是文件夹,当改文件夹下有一个init.py文件后它就成为一个package,我在这个包中引入一些py供其他py调用。

    init.py

    # -*- coding: UTF-8 -*-  
    
    # import need manager module  
    import MongoUtil  
    import FileUtil  
    import conf_dev  
    import conf_test  
    import scratch_airport_name  
    import scratch_flight_number  
    import scratch_movie_name  
    import scratch_train_number  
    import scratch_train_station  
    import MainUtil
    

    下面两个是配置文件,第一个是开发环境的(windows),第二个是测试环境的(linux),然后再根据不同系统启用不同的配置文件

    conf_dev.py

    # -*- coding: UTF-8 -*-  
    # the configuration file of develop environment  
    
    # path configure  
    data_root_path = 'E:/APK98_GNBJ_SMARTSERVER/Proj-gionee-data/smart/data'  
    
    # mongodb configure  
    user = "cmc"  
    pwd = "123456"  
    server = "localhost"  
    port = "27017"  
    db_name = "smartdb"
    

    conf_test.py

    # -*- coding: UTF-8 -*-  
    # the configuration file of test environment  
    
    #path configure  
    data_root_path = '/data/app/smart/data'  
    
    #mongodb configure  
    user = "smart"  
    pwd = "123456"  
    server = "10.8.0.30"  
    port = "27017"  
    db_name = "smartdb"
    

    下面文件是一个util文件,主要是读取原文件的内容,还有将新内容写入原文件。

    FileUtil.py

    # -*- coding: UTF-8 -*-  
    import conf_dev  
    import conf_test  
    import platform  
    
    
    # configure Multi-confronment  
    # 判断当前系统,并引入相对的配置文件
    platform_os = platform.system()  
    config = conf_dev  
    if (platform_os == 'Linux'):  
        config = conf_test  
    # path  
    data_root_path = config.data_root_path  
    
    
    # load old data  
    def read(resources_file_path, encode='utf-8'):  
        file_path = data_root_path + resources_file_path  
        outputs = []  
        for line in open(file_path, encoding=encode):  
            if not line.startswith("//"):  
                outputs.append(line.strip('\n').split(',')[-1])  
        return outputs  
    
    
    # append new data to file from scratch  
    def append(resources_file_path, data, encode='utf-8'):  
        file_path = data_root_path + resources_file_path  
        with open(file_path, 'a', encoding=encode) as f:  
            f.write(data)  
        f.close
    

    下面这个main方法控制着执行流程,其他的执行方法调用这个main方法

    MainUtil.py

    # -*- coding: UTF-8 -*-  
    
    import sys  
    from datetime import datetime  
    import MongoUtil  
    import FileUtil  
    
    # @param resources_file_path 资源文件的path  
    # @param base_url 爬取的连接  
    # @param scratch_func 爬取的方法  
    def main(resources_file_path, base_url, scratch_func):  
        old_data = FileUtil.read(resources_file_path)   #读取原资源  
        new_data = scratch_func(base_url, old_data)     #爬取新资源  
        if new_data:        #如果新数据不为空  
            date_new_data = "//" + datetime.now().strftime('%Y-%m-%d') + "\n" + "\n".join(new_data) + "\n"      #在新数据前面加上当前日期  
            FileUtil.append(resources_file_path, date_new_data)     #将新数据追加到文件中  
            MongoUtil.insert(resources_file_path, date_new_data)    #将新数据插入到mongodb数据库中  
        else:   #如果新数据为空,则打印日志  
            print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '----', getattr(scratch_func, '__name__'), ": nothing to update ")
    

    将更新的内容插入mongodb中

    MongoUtil.py

    # -*- coding: UTF-8 -*-  
    
    import platform  
    from pymongo import MongoClient  
    from datetime import datetime, timedelta, timezone  
    import conf_dev  
    import conf_test  
    
    # configure Multi-confronment  
    platform_os = platform.system()  
    config = conf_dev  
    if (platform_os == 'Linux'):  
        config = conf_test  
    # mongodb  
    uri = 'mongodb://' + config.user + ':' + config.pwd + '@' + config.server + ':' + config.port + '/' + config.db_name  
    
    
    # 将数据写入mongodb  
    # @author chenmc  
    # @param uri connect to mongodb  
    # @path save mongodb field  
    # @data save mongodb field  
    # @operation save mongodb field default value 'append'  
    # @date 2017/12/07 16:30  
    # 先在mongodb中插入一条自增数据 db.sequence.insert({ "_id" : "version","seq" : 1})  
    
    def insert(path, data, operation='append'):  
        client = MongoClient(uri)  
        resources = client.smartdb.resources  
        sequence = client.smartdb.sequence  
        seq = sequence.find_one({"_id": "version"})["seq"]      #获取自增id  
        sequence.update_one({"_id": "version"}, {"$inc": {"seq": 1}})       #自增id+1  
        post_data = {"_class": "com.gionee.smart.domain.entity.Resources", "version": seq, "path": path,  
                     "content": data, "status": "enable", "operation": operation,  
                     "createtime": datetime.now(timezone(timedelta(hours=8)))}  
        resources.insert(post_data)     #插入数据
    

    项目引入的第三方库,可使用pip install -r requirements.txt下载第三方库

    requirements.txt

    # need to install module# need to install module  
    bs4  
    pymongo  
    requests  
    json
    

    下面真正的执行方法来了,这五个py分别表示爬取五种信息:机场名、航班号、电影名、列车号、列车站。他们的结构都差不多,如下:

    第一部分:定义查找的url;
    第二部分:获取并与旧数据比较,返回新数据;
    第三部分:main方法,执行写入新数据到文件和mongodb中;
    

    scratch_airport_name.py:爬取全国机场

    # -*- coding: UTF-8 -*-  
    import requests  
    import bs4  
    import json  
    import MainUtil  
    
    resources_file_path = '/resources/airplane/airportNameList.ini'  
    scratch_url_old = 'https://data.variflight.com/profiles/profilesapi/search'  
    scratch_url = 'https://data.variflight.com/analytics/codeapi/initialList'  
    get_city_url = 'https://data.variflight.com/profiles/Airports/%s'  
    
    
    #传入查找网页的url和旧数据,然后本方法会比对原数据中是否有新的条目,如果有则不加入,如果没有则重新加入,最后返回新数据
    def scratch_airport_name(scratch_url, old_airports):  
        new_airports = []  
        data = requests.get(scratch_url).text  
        all_airport_json = json.loads(data)['data']  
        for airport_by_word in all_airport_json.values():  
            for airport in airport_by_word:  
                if airport['fn'] not in old_airports:  
                    get_city_uri = get_city_url % airport['id']  
                    data2 = requests.get(get_city_uri).text  
                    soup = bs4.BeautifulSoup(data2, "html.parser")  
                    city = soup.find('span', text="城市").next_sibling.text  
                    new_airports.append(city + ',' + airport['fn'])  
        return new_airports  
    
     #main方法,执行这个py,默认调用main方法,相当于java的main
    if __name__ == '__main__':  
        MainUtil.main(resources_file_path, scratch_url, scratch_airport_name)
    

    scratch_flight_number.py:爬取全国航班号

    #!/usr/bin/python  
    # -*- coding: UTF-8 -*-  
    
    import requests  
    import bs4  
    import MainUtil  
    
    resources_file_path = '/resources/airplane/flightNameList.ini'  
    scratch_url = 'http://www.variflight.com/sitemap.html?AE71649A58c77='  
    
    
    def scratch_flight_number(scratch_url, old_flights):  
        new_flights = []  
        data = requests.get(scratch_url).text  
        soup = bs4.BeautifulSoup(data, "html.parser")  
        a_flights = soup.find('div', class_='list').find_all('a', recursive=False)  
        for flight in a_flights:  
            if flight.text not in old_flights and flight.text != '国内航段列表':  
                new_flights.append(flight.text)  
        return new_flights  
    
    
    if __name__ == '__main__':  
        MainUtil.main(resources_file_path, scratch_url, scratch_flight_number)
    

    scratch_movie_name.py:爬取最近上映的电影

    #!/usr/bin/python  
    # -*- coding: UTF-8 -*-  
    import re  
    import requests  
    import bs4  
    import json  
    import MainUtil  
    
    # 相对路径,也是需要将此路径存入数据库  
    resources_file_path = '/resources/movie/cinemaNameList.ini'  
    scratch_url = 'http://theater.mtime.com/China_Beijing/'  
    
    
    # scratch data with define url  
    def scratch_latest_movies(scratch_url, old_movies):  
        data = requests.get(scratch_url).text  
        soup = bs4.BeautifulSoup(data, "html.parser")  
        new_movies = []  
        new_movies_json = json.loads(  
            soup.find('script', text=re.compile("var hotplaySvList")).text.split("=")[1].replace(";", ""))  
        coming_movies_data = soup.find_all('li', class_='i_wantmovie')  
        # 上映的电影  
        for movie in new_movies_json:  
            move_name = movie['Title']  
            if move_name not in old_movies:  
                new_movies.append(movie['Title'])  
        # 即将上映的电影  
        for coming_movie in coming_movies_data:  
            coming_movie_name = coming_movie.h3.a.text  
            if coming_movie_name not in old_movies and coming_movie_name not in new_movies:  
                new_movies.append(coming_movie_name)  
        return new_movies  
    
    
    if __name__ == '__main__':  
        MainUtil.main(resources_file_path, scratch_url, scratch_latest_movies)
    

    scratch_train_number.py:爬取全国列车号

    #!/usr/bin/python  
    # -*- coding: UTF-8 -*-  
    import requests  
    import bs4  
    import json  
    import MainUtil  
    
    resources_file_path = '/resources/train/trainNameList.ini'  
    scratch_url = 'http://www.59178.com/checi/'  
    
    
    def scratch_train_number(scratch_url, old_trains):  
        new_trains = []  
        resp = requests.get(scratch_url)  
        data = resp.text.encode(resp.encoding).decode('gb2312')  
        soup = bs4.BeautifulSoup(data, "html.parser")  
        a_trains = soup.find('table').find_all('a')  
        for train in a_trains:  
            if train.text not in old_trains and train.text:  
                new_trains.append(train.text)  
        return new_trains  
    
    
    if __name__ == '__main__':  
        MainUtil.main(resources_file_path, scratch_url, scratch_train_number)
    

    scratch_train_station.py:爬取全国列车站

    #!/usr/bin/python  
    # -*- coding: UTF-8 -*-  
    import requests  
    import bs4  
    import random  
    import MainUtil  
    
    resources_file_path = '/resources/train/trainStationNameList.ini'  
    scratch_url = 'http://www.smskb.com/train/'  
    
    
    def scratch_train_station(scratch_url, old_stations):  
        new_stations = []  
        provinces_eng = (  
            "Anhui", "Beijing", "Chongqing", "Fujian", "Gansu", "Guangdong", "Guangxi", "Guizhou", "Hainan", "Hebei",  
            "Heilongjiang", "Henan", "Hubei", "Hunan", "Jiangsu", "Jiangxi", "Jilin", "Liaoning", "Ningxia", "Qinghai",  
            "Shandong", "Shanghai", "Shanxi", "Shanxisheng", "Sichuan", "Tianjin", "Neimenggu", "Xianggang", "Xinjiang",  
            "Xizang",  
            "Yunnan", "Zhejiang")  
        provinces_chi = (  
            "安徽", "北京", "重庆", "福建", "甘肃", "广东", "广西", "贵州", "海南", "河北",  
            "黑龙江", "河南", "湖北", "湖南", "江苏", "江西", "吉林", "辽宁", "宁夏", "青海",  
            "山东", "上海", "陕西", "山西", "四川", "天津", "内蒙古", "香港", "新疆", "西藏",  
            "云南", "浙江")  
        for i in range(0, provinces_eng.__len__(), 1):  
            cur_url = scratch_url + provinces_eng[i] + ".htm"  
            resp = requests.get(cur_url)  
            data = resp.text.encode(resp.encoding).decode('gbk')  
            soup = bs4.BeautifulSoup(data, "html.parser")  
            a_stations = soup.find('left').find('table').find_all('a')  
            for station in a_stations:  
                if station.text not in old_stations:  
                    new_stations.append(provinces_chi[i] + ',' + station.text)  
        return new_stations  
    
    
    if __name__ == '__main__':  
        MainUtil.main(resources_file_path, scratch_url, scratch_train_station)
    

    将项目放到测试服务器(centos7系统)中运行起来,我写了一个crontab,定时调用他们,下面贴出crontab。

    /etc/crontab

    SHELL=/bin/bash  
    PATH=/sbin:/bin:/usr/sbin:/usr/bin  
    MAILTO=root  
    
    # For details see man 4 crontabs  
    
    # Example of job definition:  
    # .---------------- minute (0 - 59)  
    # |  .------------- hour (0 - 23)  
    # |  |  .---------- day of month (1 - 31)  
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...  
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat  
    # |  |  |  |  |  
    # *  *  *  *  * user-name  command to be executed  
      0  0  *  *  * root python3 /data/app/smart/py/scratch_movie_name.py    >> /data/logs/smartpy/out.log 2>&1  
      0  1  *  *  1 root python3 /data/app/smart/py/scratch_train_station.py >> /data/logs/smartpy/out.log 2>&1  
      0  2  *  *  2 root python3 /data/app/smart/py/scratch_train_number.py  >> /data/logs/smartpy/out.log 2>&1  
      0  3  *  *  4 root python3 /data/app/smart/py/scratch_flight_number.py >> /data/logs/smartpy/out.log 2>&1  
      0  4  *  *  5 root python3 /data/app/smart/py/scratch_airport_name.py  >> /data/logs/smartpy/out.log 2>&1
    

    后续

    目前项目已经正常运行了三个多月啦。。。

    有问题反馈

    在阅读与学习中有任何问题,欢迎反馈给我,可以用以下联系方式跟我交流

    • 微信公众号:裸睡的猪
    • 在下面留言
    • 直接给我私信

    关于此公众号

    • 后期或提供各种软件的免费激活码
    • 推送python,java等编程技术文章和面试技巧
    • 当然你们可以将你们感兴趣的东西直接送给我
    • 谢谢你们真诚的关注,此公众号以后获得的收益将全部通过抽奖的形式送给大家
    • 以后如果博主要创业的话,也会在此公众号中挑选小伙伴哦~
    • 希望大家分享出去,让更多想学习python的朋友看到~

     

     

    展开全文
  • python爬虫入门教程(二):开始一个简单的爬虫

    万次阅读 多人点赞 2017-09-12 15:02:21
    python爬虫入门教程,介绍编写一个简单爬虫的过程。

    2019/10/28更新

    • 使用Python3,而不再是Python2

    转载请注明出处:https://blog.csdn.net/aaronjny/article/details/77945329

    爬虫入门系列教程:


    上一篇讲了开始爬虫前的准备工作。当我们完成开发环境的安装、IDE的配置之后,就可以开始开发爬虫了。 这一篇,我们开始写一个超级简单的爬虫。

    1.爬虫的过程分析

    当人类去访问一个网页时,是如何进行的?
      ①打开浏览器,输入要访问的网址,发起请求。
      ②等待服务器返回数据,通过浏览器加载网页。
      ③从网页中找到自己需要的数据(文本、图片、文件等等)。
      ④保存自己需要的数据。

    对于爬虫,也是类似的。它模仿人类请求网页的过程,但是又稍有不同。
      首先,对应于上面的①和②步骤,我们要利用python实现请求一个网页的功能。
      其次,对应于上面的③步骤,我们要利用python实现解析请求到的网页的功能。
      最后,对于上面的④步骤,我们要利用python实现保存数据的功能。
      因为是讲一个简单的爬虫嘛,所以一些其他的复杂操作这里就不说了。下面,针对上面几个功能,逐一进行分析。

    2.如何用python请求一个网页

    作为一门拥有丰富类库的编程语言,利用python请求网页完全不在话下。这里推荐一个非常好用的第三方类库requests。

    2.1 requests

    2.1.1 安装方式

    打开终端或者cmd,在里面输入以下指令并回车

    pip3 install requests
    

    安装requests
      一般不会出什么问题,如果下载太慢,是因为pip使用的源服务器在国外,可以设置pip使用国内镜像源,设置方法可以参考PyPI使用国内源

    2.1.2 测试是否安装成功

    在命令行中输入python,敲击回车,进入python交互环境。在里面输入以下代码并回车:

    import requests
    

    如果不报错,就安装成功了,如下图:
      测试requests安装是否成功

    2.2 使用requests请求网页

    打开pycharm,创建一个项目,嗯,随便取个名字吧。
      创建项目
      创建成功后,再创建一个py文件,用来写代码。嗯,再随便取个名字= =教程(二)的2.2,那就spider_2_2_2吧。
      创建2.2.2
      在里面输入以下代码:

    #coding=utf-8
    import requests
    
    resp=requests.get('https://www.baidu.com') #请求百度首页
    print(resp) #打印请求结果的状态码
    print(resp.content) #打印请求到的网页源码
    

    对上面的代码进行以下简单的分析:
      我是用的是python2.7,第1行到第4行,都是为了将字符编码设置为utf8
      第2行:引入requests包。
      第4行:使用requests类库,以get的方式请求网址https://www.baidu.com,并将服务器返回的结果封装成一个对象,用变量resp来接收它。
      第5行:一般可以根据状态码来判断是否请求成功,正常的状态码是200,异常状态码就很多了,比如404(找不到网页)、301(重定向)等。
      第6行:打印网页的源码。注意,只是源码。不像是浏览器,在获取到源码之后,还会进一步地取请求源码中引用的图片等信息,如果有JS,浏览器还会执行JS,对页面显示的内容进行修改。使用requests进行请求,我们能够直接获取到的,只有最初始的网页源码。也正是因为这样,不加载图片、不执行JS等等,爬虫请求的速度会非常快。
      代码很短吧?一行就完成了请求,可以,这很python
      现在,运行一下代码看看吧。
      运行结果
      箭头指向的是状态码,可以看到,200,请求正常。
      被圈起来是网页的源码。

    3.如何用python解析网页源码

    网页源码我们拿到了,接下来就是要解析了。python解析网页源码有很多种方法,比如BeautifulSoup、正则、pyquery、xpath等。这里我简单介绍一下。

    3.1 网页源码解析器

    3.1.1 BeautifulSoup

    这是我比较推荐的一款解析器,简单易用,容易理解。
      但是使用bs4还需要安装另一个类库lxml,用来代替bs4默认的解析器。之所以这样做,是因为默认的那个实在太慢了,换用了lxml后,可以大幅度提升解析速度。

    3.1.1.1 安装

    命令行中输入以下指令并回车,安装bs4:

    pip3 install beautifulsoup4
    

    安装bs4
      使用pip直接安装lxml会出错,所以要用些特别的方法。Windows用户的话,去百度搜一下lxml在Windows环境下的安装方法,网上有很多,我就不多说了(主要是嫌麻烦= =)。Ubuntu用户就很方便了,在终端里面输入以下指令并回车就行了:

    apt-get install python-lxml
    

    python-lxml

    3.1.1.2 测试是否安装成功

    进入python交互环境,引用bs4和lxml类库,不报错即安装成功。

    import bs4
    import lxml
    

    bs4+lxml

    3.1.2 正则

    这个不用安装,标准库里带的就有。
      正则的优点:①速度快 ②能够提取有些解析器提取不到的数据
      正则的缺点:①不够直观,很难从面向对象的角度来考虑数据的提取 ②你得会写正则表达式
      教程就不放了,善用百度嘛。正则一般用来满足特殊需求、以及提取其他解析器提取不到的数据,正常情况下我会用bs4,bs4无法满足就用正则。
      当然了,如果你喜欢,全部用正则解析也是没问题的,你喜欢就好= =。

    3.1.3 pyquery

    这个解析器的语法和jQuery很相似,所以写过jQuery的同学用起来可能比较容易上手。国内有个dalao写的爬虫框架pyspider用的就是这个解析器。
      如果没用过jQuery,那就在bs4和pyquery两个里面选一个学吧,一般情况下会一个就够了。

    3.1.3.1 安装

    pip3 install pyquery
    

    3.1.3.2 测试

    import pyquery
    

    3.2 使用BeautifulSoup+lxml解析网页源码

    接着上面的代码来,我们使用BeautifulSoup+lxml解析请求到的网页源码。
      从百度的首页,可以通过点击跳转到很多其他页面,比如说下面圈起来的,点击都会跳转到新的页面:
      百度首页
      现在,我们想要用python获得从百度能够跳转到的页面的链接,该怎么做?
      代码很简单,接着上面的写:

    #coding=utf-8
    import requests
    from bs4 import BeautifulSoup
    
    resp=requests.get('https://www.baidu.com') #请求百度首页
    print(resp) #打印请求结果的状态码
    print(resp.content) #打印请求到的网页源码
    
    bsobj=BeautifulSoup(resp.content,'lxml') #将网页源码构造成BeautifulSoup对象,方便操作
    a_list=bsobj.find_all('a') #获取网页中的所有a标签对象
    for a in a_list:
        print(a.get('href')) #打印a标签对象的href属性,即这个对象指向的链接地址
    

    首先,第3行,引入我们解析时要使用的类库,beautifulsoup4。
      第9行,将网页的源码转化成了BeautifulSoup的对象,这样我们可以向操作DOM模型类似地去操作它。
      第10行,从这个BeautifulSoup对象中,获取所有的a标签对象(大家应该知道a标签对象是什么吧,网页中的链接绝大多数都是a对象实现的),将他们组成一个列表,也就是a_list。
      第11、12行,遍历这个列表,对于列表中的每一个a标签对象,获取它的属性href的值(href属性记录一个a标签指向的链接地址)。获取一个标签对象的属性,可以使用get(‘xx’)方法,比如a_tag是一个a标签对象,获取它的href的值,就是a_tag.get('href'),获取它的class信息可以用a_tag.get('class'),这将返回一个修饰该标签的class列表。
      运行一下,可以看到,打印出了很多链接。
      运行结果
      这是个简单的例子,介绍如何开始一个简单爬虫,不涉及复杂操作(复杂的后面会上小项目,会介绍)。关于beautifulsoup的详细用法,请自行百度。

    3.3 简单的保存数据的方法

    保存数据的方法大概可以分为几类:保存文本、保存二进制文件(包括图片)、保存到数据库。保存二进制文件和保存到数据库后面会具体说,这里简单讲一下怎么保存到文本。
      python里面操作文本相当的简单。现在,我将刚才提取出来的链接保存到一个名称为url.txt的文本里面去,将上面的代码稍作修改。

    #coding=utf-8
    import requests
    from bs4 import BeautifulSoup
    
    resp=requests.get('https://www.baidu.com') #请求百度首页
    print(resp) #打印请求结果的状态码
    print(resp.content) #打印请求到的网页源码
    
    bsobj=BeautifulSoup(resp.content,'lxml') #将网页源码构造成BeautifulSoup对象,方便操作
    a_list=bsobj.find_all('a') #获取网页中的所有a标签对象
    text='' # 创建一个空字符串
    for a in a_list:
        href=a.get('href') #获取a标签对象的href属性,即这个对象指向的链接地址
        text+=href+'\n' #加入到字符串中,并换行
    with open('url.txt','w') as f: #在当前路径下,以写的方式打开一个名为'url.txt',如果不存在则创建
        f.write(text) #将text里的数据写入到文本中
    

    代码中注释写得很清楚了,就不多做解释了。值得一提的是,使用with…as…来打开文件,在操作完成后,会自动关闭文件,不用担心忘记关闭文件了,超级好用啊!
      运行一下代码,可以发现,当前路径下多了个名为url.txt的文件。
      新文件
      打开后,能够看到我们刚才提取出来的url。
      url.txt

    4.更多

    虽然东西不多,但是写了挺长时间的。因为平时在一边上课,一边实习,时间真的不多,抽着时间一点点写的。后面我尽量加快速度写吧,当然了,尽量嘛,写得慢了的话……你顺着网线过来打我呀~
      我也只是个菜鸟,文中错误的地方,欢迎拍砖~

    展开全文
  •   大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己...

      大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行更新,博客主页:https://buwenbuhuo.blog.csdn.net/
    1

    PS:由于现在越来越多的人未经本人同意直接爬取博主本人文章,博主在此特别声明:未经本人允许,禁止转载!!!


    2


    推荐

    31
      ♥各位如果想要交流的话,可以加下QQ交流群:974178910,里面有各种你想要的学习资料。♥

      ♥欢迎大家关注公众号【不温卜火】,关注公众号即可以提前阅读又可以获取各种干货哦,同时公众号每满1024及1024倍数则会抽奖赠送机械键盘一份+IT书籍1份哟~♥
    30

    一、 分析网页结构

    以往几篇都是介绍的传统的静态界面的爬取,这次博主介绍一个爬取动态网页的超简单的一个小demo
    3
    说到动态网页,你对它了解多少呢?

    如果对动态网页不认识的童鞋,博主在此给出链接,可以看百度百科的详细解析动态网页_百度百科以及小马夫的静态页面和动态页面的区别

    4
    不要怪博主没有进行讲解,因为博主本人对与动态网页的概念也不是太过了解。等到博主整理好思绪的时候,博主会专门写一篇博文的 -。-

    简单来说,要获取静态网页的网页数据只需要给服务器发送该网页url地址就行,而动态网页的数据因为是存储在后端的数据库里。所以要获取动态网页的网页数据,我们需要向服务器发送请求文件的url地址,而不是该网页的url地址。

    🆗,下面开始进入正题。

    本篇博文就以高德地图展开:https://www.amap.com/
    5
    在打开后,我们发现有一堆div标签,但是并没有我们需要的数据,这个时候就可以判定其为动态网页,这个时候,我们就需要找接口
    8
    6
    点击网络标签,我们可以看到网页向服务器发送了很多请求,数据很多,找起来太费时间

    我们点击XHR分类,可以减少很多不必要的文件,省下很多时间。

    XHR类型即通过XMLHttpRequest方法发送的请求,它可以在后台与服务器交换数据,这意味着可以在不加载整个网页的情况下,对网页某部分的内容进行更新。也就是说,向数据库请求然后得到响应的数据是XHR类型的

    然后我们就可以在XHR类型下开始一个个找,找到了如下的数据
    7
    通过查看Headers获得URL
    9
    打开之后,我们发现其为近两天的天气情况。
    10

    打开后我们可以看到上面的情况,这是个json格式的文件。然后,它的数据信息是以字典的形式来保存的,而数据是都保存在“data”这个键值里面。

    🆗,找到了json数据,我们来对比下看是否是我们找的东西
    11
    通过对比,数据正好对应,那就说明咱们已经拿到数据了。

    二、拿到相关网址

    '''
    查询当前地点天气的url:https://www.amap.com/service/cityList?version=2020101417
    各城市对应code的url:https://www.amap.com/service/weather?adcode=410700
    
    备注:这两个url可以从Network中查看到
    '''
    

    12
    🆗,相关网址我们已经拿到了,下面就是具体的代码实现了。至于怎么实现,

    我们知道json数据可以使用response.json()转字典,然后操作字典。
    13

    三、代码实现

    知道了数据的位置后,我们开始来写代码。

    3.1 查询所有城市名称和编号

    先抓取网页,通过添加headers来伪装成浏览器来对数据库地址进行访问,防止被识别后拦截。

    url_city = "https://www.amap.com/service/cityList?version=202092419"
    
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
    }
    
    city = []
    response = requests.get(url=url_city, headers=headers)
    content = response.json()
    print(content)
    

    14
    得到我们想要的数据之后,我们通过查找可以发现cityByLetter里的编号和名称是我们需要的,那么我们就可以盘它了。
    15

        if "data" in content:
            cityByLetter = content["data"]["cityByLetter"]
            for k,v in cityByLetter.items():
                city.extend(v)
        return city
    

    15

    3.2 根据编号查询天气

    得到了编号和名称,下面肯定就是查询天气呀!

    先来看接口
    16
    通过上图,可以确定最高温度,最低温度等内容。那么就以此来进行数据爬取。

    url_weather = "https://www.amap.com/service/weather?adcode={}"
    
    response = requests.get(url=url_weather.format(adcode), headers=headers)
    content = response.json()
    item["weather_name"] = content["data"]["data"][0]["forecast_data"][0]["weather_name"]
    item["min_temp"] = content["data"]["data"][0]["forecast_data"][0]["min_temp"]
    item["max_temp"] = content["data"]["data"][0]["forecast_data"][0]["max_temp"]
    print(item)
    

    17

    🆗,我们的设想已经实现了。
    20

    四、完整代码

    # encoding: utf-8
    '''
      @author 李华鑫
      @create 2020-10-06 19:46
      Mycsdn:https://buwenbuhuo.blog.csdn.net/
      @contact: 459804692@qq.com
      @software: Pycharm
      @file: 高德地图_每个城市的天气.py
      @Version:1.0
    
    '''
    import requests
    
    
    url_city = "https://www.amap.com/service/cityList?version=202092419"
    url_weather = "https://www.amap.com/service/weather?adcode={}"
    
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
    }
    
    
    def get_city():
        """查询所有城市名称和编号"""
        city = []
        response = requests.get(url=url_city, headers=headers)
        content = response.json()
    
        if "data" in content:
            cityByLetter = content["data"]["cityByLetter"]
            for k, v in cityByLetter.items():
                city.extend(v)
        return city
    
    
    def get_weather(adcode, name):
        """根据编号查询天气"""
        item = {}
        item["adcode"] = str(adcode)
        item["name"] = name
    
        response = requests.get(url=url_weather.format(adcode), headers=headers)
        content = response.json()
        item["weather_name"] = content["data"]["data"][0]["forecast_data"][0]["weather_name"]
        item["min_temp"] = content["data"]["data"][0]["forecast_data"][0]["min_temp"]
        item["max_temp"] = content["data"]["data"][0]["forecast_data"][0]["max_temp"]
    
        return item
    
    
    def save(item):
        """保存"""
        print(item)
        with open("./weather.txt","a",encoding="utf-8") as file:
            file.write(",".join(item.values()))
            file.write("\n")
    
    
    if __name__ == '__main__':
        city_list = get_city()
        for city in city_list:
            item = get_weather(city["adcode"],city["name"])
            save(item)
    

    五、保存结果

    18
    19

    美好的日子总是短暂的,虽然还想继续与大家畅谈,但是本篇博文到此已经结束了,如果还嫌不够过瘾,不用担心,我们下篇见!


    21

      好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
      如果我的博客对你有帮助、如果你喜欢我的博客内容,请“点赞” “评论”“收藏”一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
      码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦!

    22
    23

    展开全文
  • Python爬虫入门之初遇lxml库

    万次阅读 多人点赞 2020-12-19 00:42:15
    Python爬虫入门之初遇lxml库 爬虫是什么 所谓爬虫,就是按照一定的规则,自动的从网络中抓取信息的程序或者脚本。万维网就像一个巨大的蜘蛛网,我们的爬虫就是上面的一个蜘蛛,不断的去抓取我们需要的信息。 爬虫...
  • 爬虫入门经典(十八) | 滑动验证码识别

    万次阅读 多人点赞 2020-11-10 11:09:26
      大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己...
  • 爬虫入门文章

    2018-11-30 10:49:39
    python爬虫入门之————————————————第一节–了解爬虫 python爬虫入门之————————————————第二节–使用xpath语法获取数据 python爬虫入门之————————————————第三节...
  • 网络爬虫入门到精通

    2019-04-08 17:58:39
    网络爬虫入门到精通
  • Python爬虫入门(1):综述 Python爬虫入门(2):爬虫基础了解 Python爬虫入门(3):Urllib库的基本使用 Python爬虫入门(4):Urllib库的高级用法 Python爬虫入门(5):URLError异常处理 Python爬虫...
  • java 简单爬虫入门maven项目
  • 【Python爬虫】Python爬虫入门案例

    千次阅读 多人点赞 2020-05-25 00:05:35
    Python爬虫入门案例
  • 爬虫入门经典(十七) | 图形验证码识别

    万次阅读 多人点赞 2020-11-06 12:05:41
      大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己...
  • python爬虫入门

    千次阅读 2019-08-05 10:17:47
    python爬虫入门之爬取小说 https://blog.csdn.net/qq_41813030/article/details/82764061 Python爬虫之爬取静态网站——爬取各大币交易网站公告(一) ... Python爬虫之爬取动态网站——爬取各大币交易网站公告(二....
  • 爬虫入门教程 —— 1

    万次阅读 多人点赞 2018-04-12 23:59:51
    爬虫入门教程 -1 很想做一些爬虫的基础性的教程,来与大家共同分享我的一些小经验, 我将以我认为的方式为大家讲解网络爬虫,如果你没有编程基础,对网络爬虫有兴趣,开始可能稍微有一些小难度,不过我希望能给你...
  • 爬虫入门之模拟用户请求

    万次阅读 2020-12-21 13:31:21
    接着上一篇文章Python爬虫入门之初遇lxml库,我们对爬虫程序发起的请求进行分析,爬虫爬取数据要做的就是模拟用户发起请求,接收到数据进行存储 我们先看一下一下正常的用户请求,然后再分析如何去模拟 1.正常的...
  • 爬虫入门到大牛笔记

    2020-12-02 21:02:37
    爬虫入门到大牛笔记 ,有详细的request,xpath,正则爬取方法,反爬技术,多线程,验证码破译,mongodb
  • 爬虫入门3---爬虫实战

    2019-10-23 15:23:27
    爬虫入门1---谈谈网络爬虫 爬虫入门2---爬虫框架webmagic 爬虫入门3---爬虫实战 3爬虫实战 3.1 需求 每日某时间段从****博客中爬取文档,存入文章数据库中。 3.2 数模准备 下面是****各频道地址: ...
  • 爬虫入门思维导图

    2020-01-02 16:32:11
    爬虫入门思维导图前提 前提 此图建立在理解最基础的WEB 相关协议 及基础技术后理解。 简易版爬虫入门思维导图,帮助理解整个爬虫概念。
  • Python 爬虫入门

    千次阅读 多人点赞 2019-03-13 17:15:52
    Python 爬虫入门一、准备工作1、Python安装及使用pip安装第三方库二、提取网页数据1、使用 Python 下载网页代码2、提取网页中所需内容三、一个简单的网络爬虫1、网页结构的相似性2、爬虫的基本逻辑四、存储格式化...
  • 资料仅可参考如有不妥请联系本人改正或者删除 * 2020年08月13日 python爬虫入门邓旭东 资料仅可参考如有不妥请联系本人改正或者删除 * 2020年08月13日 python爬虫入门邓旭东 资料仅可参考如有不妥请联系本人改正或者...
  • Scrapy爬虫入门教程四 Spider(爬虫)

    千次阅读 2018-07-17 17:14:07
    Scrapy爬虫入门教程一 安装和基本使用  Scrapy爬虫入门教程二 官方提供Demo  Scrapy爬虫入门教程三 命令行工具介绍和示例  Scrapy爬虫入门教程四 Spider(爬虫)  Scrapy爬虫入门教程五 Selectors(选择器)...
  • java爬虫入门示例,包含所有源码。 主要实现了爬取大众点评商户基本信息 新手入门或者参考可用
  • python3.7 scrapy简单爬虫入门基于 http://www.okhqb.com/ 网站的简单示例。。
  • 爬虫入门1---谈谈网络爬虫 爬虫入门2---爬虫框架webmagic 爬虫入门3---爬虫实战 1 谈谈网络爬虫 1.1 什么是网络爬虫 网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,可以自动化浏览网络中的信息,当然浏览...
  • Python基础与爬虫入门ppt+代码
  • Python爬虫入门学习实践——爬取小说

    千次阅读 多人点赞 2020-12-26 00:20:04
    Python爬虫入门学习实践——爬取小说 前言 本学期开始接触python,python是一种面向对象的、解释型的、通用的、开源的脚本编程语言,我觉得python最大的优点就是简单易用,学习起来比较上手,对代码格式的要求没有...
  • CSDN自动签到器,送给凌晨5点还没有下班的你,Python爬虫入门教程 90-100,爬虫百例教程

空空如也

1 2 3 4 5 ... 20
收藏数 18,561
精华内容 7,424
关键字:

爬虫入门

爬虫 订阅