精华内容
下载资源
问答
  • 由于时间的推移,嵩天老师17年的代码由于网站的反爬虫机制,需要在原有基础上加入对user-agent的虚拟才可以正常使用授课用的实例网站 www.ip138.com PS:现在大多数网站都需要进行User-Agent的虚拟以及cookie的虚拟...

            由于时间的推移,嵩天老师17年的代码由于网站的反爬虫机制,需要在原有基础上加入对user-agent的虚拟才可以正常使用授课用的实例网站  www.ip138.com

    PS:现在大多数网站都需要进行User-Agent的虚拟以及cookie的虚拟,将其放入headers字典里可以实现虚拟。

    原代码(为了便于理解,我简化了代码):

    import requests
    url='https://m.ip138.com/iplookup.asp?ip=202.204.80.112'
    try:
        r=requests.get(url,headers=headers)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(r.text)
    except:
        print("爬取失败")
    

    改进代码(加入了对user-agent的虚拟):

    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
    }

    完整代码:

    import requests
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
    }
    url='https://m.ip138.com/iplookup.asp?ip=202.204.80.112'
    try:
        r=requests.get(url,headers=headers)
        r.raise_for_status()
        r.encoding=r.apparent_encoding
        print(r.text)
    except:
        print("爬取失败")
    

    结果:

    展开全文
  • Python爬虫笔记·嵩天

    2021-01-21 23:56:51
    Python爬虫笔记Resquest库HTTP协议Beautiful Soup库正则表达式:Scrapy框架创建项目:在工程中产生爬虫配置产生的spider爬虫yield 关键字Scrapy爬虫的使用步骤:Scrapy爬虫的数据类型:Request类:Response类:Item类: ...

    Resquest库

    r = requests.get(url, params=None,**kwargs)
    requests是一个response对象

    主要方法:
    requests.request() 构造一个请求,支撑一下各方法
    requests.get() 获取网页
    requests.head () 获取头信息
    requests.post() 提交POST请求
    requests.put() 提交PUT请求
    requests.patch() 提交局部修改请求
    requests.delete() 提交删除请求

    response对象的属性:
    r.status_code HTTP请求返回状态,200成功,404失败
    r.text HTTP响应内容的字符串形式,即url对应的页面内容
    r.encoding 从HTTPheader中猜测的响应内容编码方式
    r.apparent_encoding从内容中分析的响应内容编码方式,备选
    r.contemt HTTP响应的二进制形式

    错误处理:
    requests.ConnectionError 网络连接异常 DNA异常拒绝连接
    requests.HTTPError HTTP错误异常
    requests.URLRequired URL缺失异常
    requests.TooManyRedirects超过最大重定向次数
    requests.ConnectTimeout连接远程服务器超时异常,仅连接
    requests.Timeout请求URL超时产生异常,全过程

    r.raise_for_status()
    如果不是200,产生异常requests. HTTPError

    #requests尝试
    import requests
    r = requests.get("http://lexue.bit.edu.cn/504.html")
    r.encoding = 'utf-8'
    print(r.text)
    print(r.status_code)
    type(r)
    r.headers
    
    #爬取网页常用代码
    import requests
    
    def getHTMLText(url):
        try:
            r = requests.get(url,timeout=30)
            r.raise_for_status()
            #如果状态不是200,引发HTTPError异常
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return "异常"
    
    
    url = "www.baidu.com"
    print(getHTMLText(url))
    
    #爬取京东
    import requests
    
    r = requests.get("https://item.jd.com/100007652174.html")
    print(r.status_code)
    print(r.encoding)
    print(r.text[:1000])
    
    #爬取亚马逊
    import requests
    
    url="https://www.amazon.cn/dp/B07746N2J9/ref=sr_1_1?__mk_zh_CN=%E4%BA%9A%E9%A9%AC%E9%80%8A%E7%BD%91%E7%AB%99&keywords=kindle&qid=1583392394&sr=8-1"
    r = requests.get(url)
    print(r.status_code)
    print(r.encoding)
    #r.encoding = r.apparent_encoding
    #print(r.text[:1000])
    print(r.request.headers)
    print("\n以上查询信息到错误信息,下面来修改访问方式")
    kv = {'user-agent':'Mozilla/5.0'}
    r = requests.get(url,headers=kv)
    print(r.status_code)
    print("此时访问状态正常")
    print(r.text[1000:2000])
    
    #百度网页提交
    import requests
    
    #baidu API:
    #http://www.baidu.com/s?wd= keyword
    #360 API:
    #http://www.so.com/s?q= keyword
    
    kv = {'wd':'Python'}
    r = requests.get("http://www.baidu.com/s",params=kv)
    print(r.status_code)
    print("以下告知我们请求baidu的信息")
    r.raise_for_status()
    print(r.request.url)
    print("长度为:{}".format(len(r.text)))
    print(r.text[:1000])
    
    import requests
    
    path = "E:/abc.mp4"
    url = "http://lexue.bit.edu.cn/pluginfile.php/232851/mod_folder/content/0/%E8%A7%86%E9%A2%91/%E6%95%99%E5%AD%A6%E8%A7%86%E9%A2%91%EF%BC%88%E6%8E%88%E8%AF%BE%E5%BD%95%E5%83%8F%EF%BC%89/6.5%20%E6%A0%B7%E5%BC%8F%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%8826%E5%88%86%E9%92%9F%EF%BC%8C55M%EF%BC%89.mp4"
    r = requests.get(url)
    print(r.status_code)
    with open(path, 'wb') as f:
        f.write(r.content)
    f.close
    
    #ip查询
    import requests
    
    url="http://www.ip138.com/ip.php?ip="
    r = requests.get(url+"202.204.80.112")
    print(r.status_code)
    print(r.text[-500:])
    

    HTTP协议

    基于请求与响应模式的,无状态的应用层协议
    URL: https://host[:port][path]
    post:端口号,缺省值为80
    path:请求资源的路径

    requests.request(method, url, **kwargs)
    method:请求方式
    r= requests.request(‘GET’,url,**kwargs)
    r= requests.request(‘HEAD’,url,**kwargs)
    r= requests.request(‘POST’,url,**kwargs)
    r= requests.request(‘PUT’,url,**kwargs)
    r= requests.request(‘PATCH’,url,**kwargs)
    r= requests.request(‘delete’,url,**kwargs)
    r= requests.request(‘OPTIONS’,url,**kwargs)
    **kwargs:控制访问的参数 13个
    params:字典或字节序列,作为参数增加到url中
    data:字典、字节序列或文件对象,作为Request内容
    json:JSON格式的数据,作为Request内容
    headers:字典,HTTP定制头
    cookies:字典或CookieJar, Request中的cookie
    auth:元组,支持HTTP认证功能
    files:字典类型,传输文件
    timeout:设定超时时间,单位:s
    proxies:字典类型,设定访问代理服务器,增加登录认证
    allow_redirects: True/False,默认为True,重定向开关
    stream:True/False,默认为True,获取内容立即下载开关
    verify:True/False,默认为True,认证SSL证书开关
    cert:本地SSL证书路径

    requests.get(url,params=None,**kwargs)
    **kwargs:12个,除了params
    requests.head(url, **kwargs)
    requests.post(url,data=None,json=None,**kwargs)
    **kwargs:11个,除了data, json
    requests.put(url,data=None, **kwargs)
    **kwargs:12个,除了data
    requests.patch(url,data=None, **kwargs)
    **kwargs:12个,除了data
    requests.delete(url, **kwargs)

    from bs4 import BeautifulSoup
    import requests
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    print(soup.head)
    print("子目录:",end="")
    print(soup.head.contents)
    print("")
    print(soup.body.contents)
    print("儿子有几个?{}".format(len(soup.body.contents)))
    print("打印第一个:",end="")
    print(soup.body.contents[1])
    
    #优化HTML可读性
    from bs4 import BeautifulSoup
    import requests
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    #设置换行来优化
    print(soup.prettify())
    

    Beautiful Soup库

    <p class= “titlr”>…</p>标签
    名称,属性
    Tag:标签,最基本的信息组织单元,用<></>标明开头结尾
    Name:标签的名字,

    的名字是p,用.name获取
    Attributes:标签的属性,字典形式组织,用.attrs
    NavigableString:标签内非属性字符串<>…</>中字符串, <tag>.string
    Comment:标签内字符串的注释部分,一种特殊的Comment类型
    HTML结构:
    下行遍历:
    .contents 获得子节点列表
    .children 子节点的迭代类型,与content类似
    .descendants子孙节点迭代类型,包含所有子孙节点
    上行遍历:
    .parent节点的父亲标签
    .parents节点先辈标签的迭代类型
    平行遍历:
    .next_sibling 返回按HTML文本顺序的下一个平行节点标签
    .previous_sibling返回按HTML文本顺序的上一个平行节点标签
    .next_siblings迭代类型,返回后续所有平行节点标签
    .previuos_siblings迭代类型,返回前续所有平行节点标签
    #测试
    from bs4 import BeautifulSoup
    import requests
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    #print(demo)
    soup = BeautifulSoup(demo, "html.parser")
    #print(soup.prettify())#全部内容
    
    print(soup.title)
    print(soup.a)#获取"链接"标签
    print(soup.a.name)#获取a标签的名字
    print(soup.a.parent.name)#获得上一层标签名字
    print(soup.a.parent.parent.name)#获得上上一层标签名字
    
    print(soup.a.attrs)#获取标签和属性
    print(soup.a.attrs['class'])#获取属性字典对应的值
    print(soup.a.attrs['class'])#获取属性字典对应的值
    print(type(soup.a.attrs))#这是一个字典类型
    print(soup.a.string)
    
    print("ssssssssssssssssssssssssss")
    print(soup.p)
    print(soup.p.string)
    
    #查找链接
    from bs4 import BeautifulSoup
    import requests
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    for link in soup.find_all("a"):
        print(link.get('href'))
    
    #分类提取
    from bs4 import BeautifulSoup
    import requests
    import re
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    for tag in soup.find_all(re.compile('b')):
        print(tag.name)
    #仅提取b中的tag
    print(soup.find_all('p','course'))
    print(soup.find_all(id='link1'))
    print(soup.find_all(id='link'))
    
    print(soup.find_all(id=re.compile('link')))
    
    #信息展示
    from bs4 import BeautifulSoup
    import requests
    
    r = requests.get("https://python123.io/ws/demo.html")
    demo = r.text
    soup = BeautifulSoup(demo, "html.parser")
    print(soup.find_all('a'))
    print(soup.find_all(['a','b']))
    
    #大学排名A
    #CrawUnivRankingA.py
    from bs4 import BeautifulSoup
    import requests
    import bs4
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
     
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):#检测标签类型
                tds = tr('td')
                ulist.append([tds[0].string, tds[1].string, tds[3].string])
     
    def printUnivList(ulist, num):
        print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分"))
        for i in range(num):
            u=ulist[i]
            print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2]))
         
    def main():
        uinfo = []
        url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
        html = getHTMLText(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 18)
    main()
    
    #大学排名B
    #CrawUnivRankingB.py
    import requests
    from bs4 import BeautifulSoup
    import bs4
     
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
     
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr('td')
                ulist.append([tds[0].string, tds[1].string, tds[3].string])
     
    def printUnivList(ulist, num):
        tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
        print(tplt.format("排名","学校名称","总分",chr(12288)))
        for i in range(num):
            u=ulist[i]
            print(tplt.format(u[0],u[1],u[2],chr(12288)))
         
    def main():
        uinfo = []
        url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
        html = getHTMLText(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 20) # 20 univs
    
    #股票信息查询A
    #CrawBaiduStocksA.py
    import requests
    from bs4 import BeautifulSoup
    import traceback
    import re
     
    def getHTMLText(url):
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
     
    def getStockList(lst, stockURL):
        html = getHTMLText(stockURL)
        soup = BeautifulSoup(html, 'html.parser') 
        a = soup.find_all('a')
        for i in a:
            try:
                href = i.attrs['href']
                lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
            except:
                continue
     
    def getStockInfo(lst, stockURL, fpath):
        for stock in lst:
            url = stockURL + stock + ".html"
            html = getHTMLText(url)
            try:
                if html=="":
                    continue
                infoDict = {}
                soup = BeautifulSoup(html, 'html.parser')
                stockInfo = soup.find('div',attrs={'class':'stock-bets'})
     
                name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
                infoDict.update({'股票名称': name.text.split()[0]})
                 
                keyList = stockInfo.find_all('dt')
                valueList = stockInfo.find_all('dd')
                for i in range(len(keyList)):
                    key = keyList[i].text
                    val = valueList[i].text
                    infoDict[key] = val
                 
                with open(fpath, 'a', encoding='utf-8') as f:
                    f.write( str(infoDict) + '\n' )
            except:
                traceback.print_exc()
                continue
     
    def main():
        stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
        stock_info_url = 'https://gupiao.baidu.com/stock/'
        output_file = 'D:/BaiduStockInfo.txt'
        slist=[]
        getStockList(slist, stock_list_url)
        getStockInfo(slist, stock_info_url, output_file)
     
    main()
    
    #股票信息查询B
    #CrawBaiduStocksB.py
    import requests
    from bs4 import BeautifulSoup
    import traceback
    import re
     
    def getHTMLText(url, code="utf-8"):
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = code
            return r.text
        except:
            return ""
     
    def getStockList(lst, stockURL):
        html = getHTMLText(stockURL, "GB2312")
        soup = BeautifulSoup(html, 'html.parser') 
        a = soup.find_all('a')
        for i in a:
            try:
                href = i.attrs['href']
                lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
            except:
                continue
     
    def getStockInfo(lst, stockURL, fpath):
        count = 0
        for stock in lst:
            url = stockURL + stock + ".html"
            html = getHTMLText(url)
            try:
                if html=="":
                    continue
                infoDict = {}
                soup = BeautifulSoup(html, 'html.parser')
                stockInfo = soup.find('div',attrs={'class':'stock-bets'})
     
                name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
                infoDict.update({'股票名称': name.text.split()[0]})
                 
                keyList = stockInfo.find_all('dt')
                valueList = stockInfo.find_all('dd')
                for i in range(len(keyList)):
                    key = keyList[i].text
                    val = valueList[i].text
                    infoDict[key] = val
                 
                with open(fpath, 'a', encoding='utf-8') as f:
                    f.write( str(infoDict) + '\n' )
                    count = count + 1
                    print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
            except:
                count = count + 1
                print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
                continue
     
    def main():
        stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
        stock_info_url = 'https://gupiao.baidu.com/stock/'
        output_file = 'D:/BaiduStockInfo.txt'
        slist=[]
        getStockList(slist, stock_list_url)
        getStockInfo(slist, stock_info_url, output_file)
     
    main()
    
    # CrowTaobaoPrice.py
    import requests
    import re
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def parsePage(ilt, html):
        try:
            plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html)
            tlt = re.findall(r'\"raw_title\"\:\".*?\"', html)
            for i in range(len(plt)):
                price = eval(plt[i].split(':')[1])
                title = eval(tlt[i].split(':')[1])
                ilt.append([price, title])
        except:
            print("")
    
    def printGoodsList(ilt):
        tplt = "{:4}\t{:8}\t{:16}"
        print(tplt.format("序号", "价格", "商品名称"))
        count = 0
        for g in ilt:
            count = count + 1
            print(tplt.format(count, g[0], g[1]))
    
    def main():
        goods = 'book'
        depth = 3
        start_url = 'https://s.taobao.com/search?q=' + goods + '&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306&bcoffset=3&ntoffset=3&p4ppushleft=1%2C48'
        infoList = []
        for i in range(depth):
            try:
                url = start_url + '&s=' + str(44 * i)
                html = getHTMLText(url)
                parsePage(infoList, html)
            except:
                continue
        printGoodsList(infoList)
    
    main()
    

    正则表达式:

    .表示任何单个字符
    []字符集,对单个字符给出取值范围[abc]表示a,b,c
    [^]非字符集, 对单个字符给出排除范围
    *字符0次或无限次扩展,abc*表示ab,abc,abcc,abccc
    +字符1次或无限次扩展,abc+表示abc,abcc,abccc
    ?字符0次或1次扩展,abc?表示ab,abc
    |左右表达式任意一个
    {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)
    \d数字,等价于[0-9]
    \w单词字符,等价于[A-Z,a-z,0-9,_]

    实例:
    P(Y|YT|YTH|YTHO)?N PN,PYN,PYTN,PYTHN,PYTHON
    PY[TH]ON PYTON,PYHON
    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] 匹配中文字符
    (([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地址0-255

    re库采用raw string类型表示正则表达式,表示为:r‘text’
    raw string 不包含转义符的字符串

    Re库主要功能函数:

    • re.search()
      在一个字符串中搜索匹配正则表达式,返回match对象
      re.search(pattern,string,flags=0)
      pattern原文段, string待匹配字符串
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
    • re.match()
      在一个字符串的开始位置起搜索匹配正则表达式,返回match对象
      re.match(pattern,string,flags=0)
      pattern原文段, string待匹配字符串
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
    • re.findall()
      搜索字符串,以列表类型返回全部能匹配的子串
      re.findall(pattern,string,flags=0)
      pattern原文段, string待匹配字符串
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
    • re.split()
      将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
      re.split(pattern,string,maxsplit=0,flags=0)
      pattern原文段, string待匹配字符串
      maxsplit:最大分割数,剩余部分作为最后一个元素输出
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
    • re.finditer()
      搜索字符串,返回一个匹配结果的迭代类型,适用于for
      re.finditer(pattern,string,flags=0)
      pattern原文段, string待匹配字符串
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
    • re.sub()替换符合的内容,返回替换后的字符串
      re.sub(pattern,repl,string,count=0,flags=0)
      pattern原文段
      repl:替换匹配字符串的字符串
      string待匹配字符串
      flags:
      re.I 忽略大小写,[A-Z]能匹配小写字符
      re.M 将开始部分变为每行的开始的部分
      re.S .匹配所有字符包括换行
      count:匹配的最大替换次数

    Match对象的属性:
    .string 待匹配文本
    .re 匹配时使用的pattern对象
    .pos 正则表达式搜索文本开始位置
    .endpos正则表达式搜索文本结束位置

    Match对象的方法:
    .group(0) 获得匹配后的字符串
    .start()匹配字符串在原始字符串的开始位置
    .end()匹配字符串在原始字符串的结束位置
    .span() 返回(.start(),.end())

    贪婪匹配:默认即输出最长的子串

    >>>match = re.search(r‘PY.*N’,‘PYANBNCNDN’)
    >>>match.group(0)
    	‘PYANBNCNDN’
    

    最小匹配:最小匹配

    >>>match = re.search(r‘PY.*?N’,‘PYANBNCNDN’)
    >>>match.group(0)
    	‘PYAN’
    

    最小匹配操作符:
    *? 前一个字符0次或无限次扩展
    +? 前一个字符1次或无限次扩展
    ?? 前一个字符0次或1次扩展
    {m,n} 扩展前一个字符m至n次含n

    Scrapy框架

    Engine:
    不需要用户修改
    控制所有模块之间的数据流
    根据条件触发事件
    Downloader:
    不需要用户修改
    根据请求下载网页
    Scheduler:
    不需要用户修改
    对所有爬取请求进行调度管理
    Downloader Middleware为使用户修改Downloader形成:
    目的:实现Engine Downloader Scheduler之间用户配置
    功能:修改,丢弃,新增请求或响应
    Spider:
    需要用户编写配置代码
    解析Downloader返回的响应(Response)
    产生爬取项(scraped item)
    产生额外的爬取请求(Request)
    Item Pipelines:
    以流水线方式处理Spider产生的爬取项
    由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline
    可能操作包括:清理,检验和查重爬取项中的HTML数据,将数据存到数据库
    Spider Middleware:
    用户编写配置代码
    目的:对请求和爬取项再处理
    功能:修改,丢弃,新增请求或爬取项

    Requests VS Scrapy
    两者都不可处理js,提交表单,应对验证码等功能

    Scrapy命令行格式:>scrapy<command>[options][args]
    scrapy startproject [dir] 创建一个新工程
    scrapy genspider [options] 创建一个爬虫
    scrapy settings [options] 获得爬虫配置信息
    scrapy crawl 运行一个爬虫
    scrapy list 列出工程中所有爬虫
    scrapy shell [url] 启动URl 调试命令行

    创建项目:

    scrapy startproject python123demo
    python123demo/ 外层目录
    scrapy.cfg 部署Scrapy 爬虫的配置文件
    python123demo/ Scrapy框架的用户自定义Python代码
    init.py 初始化脚本,无需修改
    items.py Items代码模板(继承类)
    middlewares.py Middlewares 代码模板(继承类)
    pipelines.py Pipelines代码模板(继承类)
    settings.py Scrapy 爬虫的配置文件
    spiders/ Spiders代码模板目录(继承类)
    init.py 初始文件,无需修改
    pycache/ 缓存目录,无需修改

    在工程中产生爬虫

    scrapy genspider demo python123.io生成一个名为demo的spider

     -*- coding: utf-8 -*-
    import scrapy
    
    class DemoSpider(scrapy.Spider):
       	name = 'demo'
     	   allowed_domains = ['python123.io']
      	   start_urls = ['http://python123.io/']
    
       	def parse(self, response):
        	    pass
    

    parse()用于处理响应,解析内容形成字典,发现新的URL爬取请求

    配置产生的spider爬虫

    class DemoSpider(scrapy.Spider):
        name = "demo"
        # allowed_domains = ['python123.io']
        start_urls = ['http://python123.io/ws/demo.html']
    
    	def parse(self, response):
            fname = response.url.split('/')[-1]
            with open(fname, 'wb') as f:
                f.write(response.body)
            self.log('Saved file %s' % name)
    
    	也可以修改为:
    	def start_requests(self):
    		urls = [ 'http://python123.io/ws/demo.html' ]
    		for url in urls:
    			yield scrapy.Request(url=url, callback=self.parse)
    

    yield 关键字

    生成器是一个不断产生值的函数
    包含yield语句的函数是一个生成器
    生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值

    yield写法:

    	>>> def gen(n):
    				for i in range(n):
    					yield i**2
    	>>> for i in gen(5):
    				print(i)
    	普通写法:
    	>>> def square(n):
    				ls = [i**2 for I in range(n)]
    				return ls
    	>>> for i in square(5):
    				print(i)
    

    Scrapy爬虫的使用步骤:

    1. 创建一个工程和Spider模板
    2. 编写Spider
    3. 编写Item Pipeline
    4. 优化配置策略

    Scrapy爬虫的数据类型:

    Request 类
    Response 类
    Item 类

    Request类:

    class scrapy.http.Request()
    Request对象表示一个HTTP请求
    由Spider生成,由Downloader执行

    .url Request对应的请求URl地址
    .method 对应的请求方法, ‘GET’ ‘POST’等
    .headers 字典类型风格的请求头
    .body 请求内容主题,字符串类型
    

    .meta 用户添加的扩展信息,在Scrapy内部模块间传递信息使用
    .copy() 复制该请求

    Response类:

    class scrapy.http.Response()
    Response对象表示一个HTTP响应
    由Downloader生成,由Spider处理

    .url Response对应的请求URl地址
    .status HTTP状态码,默认是200
    .headers Response对应的头部信息
    .body Response对应的内容信息,字符串类型
    .flags 一组标记
    

    .request产生Response类型对应的Request对象
    .copy() 复制该响应

    Item类:

    class scrapy.item.Item()
    Item对象表示一个从HTML页面中提取的信息内容
    由Spider生成,由Item Pipeline处理
    Item类似字典类型,可以按照字典类型操作
    可以使用CSS Selector:
    <HTML>.css(‘a::atter(href)’).extract()
    标签名称 标签属性

    settings.py文件
    CONCURRENT_REQUESTS Downloader最大并发请求下载数量,默认32
    CONCURRENT_ITEMS Item Pipeline最大并发ITEM处理数量,默认100
    CONCURRENT_REQUESTS_PER_DOMAIN每个目标域名最大的并发请求数量,默认8
    CONCURRENT_REQUESTS_PER_IP 每个目标IP最大的并发请求数量,默认0,非0有效

    展开全文
  • 但是与嵩天老师的课件中不同的是包含大学名称的标签是 td 下的 a 标签。 所以问题应该是出在获取大学名称部分。 将打印 ulist 的内容打印出来。 代码如下: 将语句: ulist.append([tds[0].string, tds[1].string, ...

    首先附上课程中程序,无法正常运行

    把2016年的url更改为今年的url:http://www.shanghairanking.cn/rankings/bcur/2020

    代码如下:

    import requests
    from bs4 import BeautifulSoup
    import bs4
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr('td')
                ulist.append([tds[0].string, tds[1].string, tds[3].string])
    
    def printUnivList(ulist, num):
        print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分"))
        for i in range(num):
            u=ulist[i]
            print("{:^10}\t{:^6}\t{:^10}".format(u[0],u[1],u[2]))
        
    def main():
        uinfo = []
        url = 'http://www.shanghairanking.cn/rankings/bcur/2020'
        html = getHTMLText(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 20) # 20 univs
    main()
    

    输出结果:

    报错
    AttributeError: ‘NoneType’ object has no attribute ‘children’

    寻找问题原因

    先输出网站内容,代码如下:

    from bs4 import BeautifulSoup
    import requests
    r = requests.get('https://www.shanghairanking.cn/rankings/bcur/2020')
    r.encoding = r.apparent_encoding
    demo = r.text
    soup = BeautifulSoup(demo,'html.parser')
    print(soup.prettify())
    

    部分输出结果:

    截取部分输出结果
    输出结果中可以看到 tbody 标签包含所有大学的信息,tr 标签包含一个大学的全部信息,td 标签下包含单个大学的每个信息。 但是与嵩天老师的课件中不同的是包含大学名称的标签是 td 下的 a 标签。
    所以问题应该是出在获取大学名称部分。
    将打印 ulist 的内容打印出来。

    代码如下:

    将语句:

    ulist.append([tds[0].string, tds[1].string, tds[4].string])
    

    改为 :

    ulist.append([tds[0].string, tds[1], tds[4].string])
    
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr('td')
                ulist.append([tds[0].string, tds[1], tds[4].string])
        print(ulist)
    

    输出结果:

    在这里插入图片描述
    可以看到我们想要的内容被打印出来了,但是还有一下我们不想要的内容。
    可以看到我们想要的内容在 a 标签下,可以用 .find() 方法检索出我们想要的内容。

    代码如下:

    for a in tr.find('a'):
    	print('a')
    

    输出结果为:

    在这里插入图片描述
    这正是我们想要的内容,并把它赋给 tds。

    代码如下:

    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr('td')
    #            ulist.append([tds[0].string, tds[1], tds[4].string])
                for a in tr.find('a'):
    #                print(a)
                    ulist.append([tds[0].string, a, tds[4].string])
    

    输出结果为:

    在这里插入图片描述
    内容正是我们想要的,但是排版不够整齐。原因是 ulist 的内容里面含有换行符。
    把ulist里面的换行符用 .replace() 方法替换掉,就不会有换行的问题了。

    代码如下:

    def printUnivList(ulist, num):
        print("{:^10}\t{:^6}\t{:^10}".format("排名","学校名称","总分"))
        for i in range(num):
            u=ulist[i]
            print("{:^10}\t{:^6}\t{:^10}".format(u[0].replace('\n',''), u[1].replace('\n',''), u[2].replace('\n','')))
    

    输出结果:

    在这里插入图片描述
    这正是我们想要的排版和内容,修改一下print() 打印出来的格式就能得到比较整齐的排版了。

    程序整体代码如下:

    import requests
    from bs4 import BeautifulSoup
    import bs4
    
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, "html.parser")
        for tr in soup.find('tbody').children:
            if isinstance(tr, bs4.element.Tag):
                tds = tr('td')
    #            ulist.append([tds[0].string, tds[1], tds[4].string])
                for a in tr.find('a'):
    #                print(a)
                    ulist.append([tds[0].string, a, tds[4].string])
        
    def printUnivList(ulist, num):
        print("     {:^10}\t{:^6}\t      {:^10}".format("排名","学校名称","总分"))
        for i in range(num):
            u=ulist[i]
            print("{:^10}\t{:^6}\t{:^10}".format(u[0].replace('\n',''), u[1].replace('\n',''), u[2].replace('\n','')))
        
    def main():
        uinfo = []
        url = 'http://www.shanghairanking.cn/rankings/bcur/2020'
        html = getHTMLText(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 20) # 20 univs
    main()
    

    输出结果为:

    在这里插入图片描述

    这个排名的网站又更新了,上面的程序用不了了,下面是更新之后的程序:

    
    import requests
    from bs4 import BeautifulSoup
    import bs4
    
    def getHTMLtext(url):
        try:
            r = requests.get(url)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return ""
    
    def fillUnivList(ulist, html):
        soup = BeautifulSoup(html, 'html.parser')
        for tr in soup.find('tbody').children:
            #detect the type of the tr, filte out tr that type is not bs4.element.Tag
            if isinstance(tr, bs4.element.Tag): 
                #creating a list containing the tag:'td'
                tds = tr('td')
                for a in tr.find('a'):
                    continue
                for b in tr.find('td'):
                    ulist.append([b, a])
    
    def printUnivList(ulist, num):
        print("       {:^10}\t     {:^6}\t".format("uni_ranking", "uni_name"))
        for i in range(0,num,2):
            u = ulist[i]
    
            print("{:^10}\t{:^16}".format(u[0].replace('\n',''), u[1].replace('\n','')))
    
    
    def main():
        uinfo = []
        url = 'http://www.shanghairanking.cn/rankings/bcur/2020'
        html = getHTMLtext(url)
        fillUnivList(uinfo, html)
        printUnivList(uinfo, 20)
    main()
    
    

    输出结果:

    在这里插入图片描述

    以下是淘宝商品爬虫代码:

    因为淘宝网的反爬虫机制,所以需要伪装一下爬虫

    import requests
    import re
    
    def getHTMLText(url):
        try:
            header = {
        'authority': 's.taobao.com',
        'cache-control': 'max-age=0',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 Edg/86.0.622.61',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-user': '?1',
        'sec-fetch-dest': 'document',
        'referer': 'https://www.taobao.com/',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
        'cookie': 't=45617de446470fd44aee6d085f2d9e18; cna=SwSKFeQJLyYCATsqJmaw9KmK; miid=488275361906276349; tg=0; _m_h5_tk=7e994d481264fc9b7909a2fda08a7f77_1604587354537; _m_h5_tk_enc=dd8e40d0dd3512737c7a628d7ca28d87; v=0; _tb_token_=e3e5e7fbb0551; enc=d6kXYOkMlGO4Vpc3fpc0k15%2BptSme%2Fhs4qGftdmvi0gB595cZ8lCtM4ODRPLW8NsrIFzT1l8rh%2Fw974tqE3%2BKA%3D%3D; alitrackid=www.taobao.com; lastalitrackid=www.taobao.com; cookie2=14809c047547fa2b6897acb65a316e0f; hng=CN%7Czh-CN%7CCNY%7C156; xlly_s=1; thw=cn; _samesite_flag_=true; JSESSIONID=EA7B34945DCBBAC8990AED7A7D51BFFC; isg=BAsLXFa90HFmcQ6XrwKaebexmq_1oB8iJCKJQn0IP8oUnCn-BXX8cpZ9c5xy6Xca; l=eBj929xIqLsfyQIdBO5aourza77tzIRbzmFzaNbMiInca1uhtn6hnNQVmWH9SdtxgtCecetyM85CqdnprdadNxDDBexrCyCurxvO.; tfstk=cDaPBQx4raQrbrgCX4geVdyLTxiRaQ435ghKqkJ3LEs2KgqsQs4kpj4DB8eeH-nl.',
        }
            r=requests.get(url,timeout=30,headers=header)
            r.raise_for_status()
            r.encoding=r.apparent_encoding
            return r.text
        except:
            return ""
        print("")
        
    def parsePage(ilt,html):
        try:
            plt=re.findall(r'"view_price":"[\d.]*"',html) 
            tlt=re.findall(r'"raw_title":".*?"',html) #最小匹配
            for i in range(len(plt)):
                price=eval(plt[i].split(':')[1]) #eval去除引号
                title=eval(tlt[i].split(':')[1])
                ilt.append([price,title])#输出由多个列表组成的列表
    #        print(ilt)
            
        except:
            print("")
        
    def printGoodsList(ilt):
        tplt="{:4}\t{:8}\t{:10}"
        print(tplt.format('序号','价格','商品名称'))
        count=0
        for g in ilt:
            count+=1
            print(tplt.format(count,g[0],g[1]))
        print("")
        
    def main():
        goods='jetson'
        depth=2
        start_url='https://s.taobao.com/search?q='+goods
        infoList=[]
        for i in range(depth):
            try:
                url=start_url+'&s='+str(44*i)
                html=getHTMLText(url)
                parsePage(infoList,html)
            except:
                continue
        printGoodsList(infoList)
        
    main()
    
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 715
精华内容 286
关键字:

python爬虫嵩天

python 订阅
爬虫 订阅