爬虫

 

 

 

###################################################

一、什么是爬虫?    

  爬虫:就是抓取网页数据的程序。

二、爬虫怎么抓取网页数据:    

  网页三大特征:

    -1. 网页都有自己唯一的URL(统一资源定位符)来进行定位    

    -2. 网页都使用HTML(超文本标记语言)来描述页面信息。    

    -3. 网页都使用HTTP/HTTPS(超文本传输协议)协议来传输HTML数据。

  爬虫的设计思路:    

    -1. 首先确定需要爬取的网页URL地址。    

    -2. 通过HTTP/HTTP协议来获取对应的HTML页面。    

    -3. 提取HTML页面里有用的数据:        

      a. 如果是需要的数据,就保存起来。        

      b. 如果是页面里的其他URL,那就继续执行第二步。

三、为什么选择Python做爬虫?

  - PHP 虽然是世界上最好的语言,但是他天生不是干这个的,而且对多线程、异步支持不够好,并发处理能力很弱。 爬虫是工具性程序,对速度和效率要求比较高。

  - Java 的网络爬虫生态圈也很完善,是Python爬虫最大的对手。但是Java语言本身很笨重,代码量很大。重构成本比较高,任何修改都会导致代码的大量变动。爬虫经常需要修改部分采集代码。

  - C/C++ 运行效率和性能几乎最强,但是学习成本很高,代码成型比较慢。能用C/C++做爬虫,只能说是能力的表现,但是不是正确的选择。

  - Python 语法优美、代码简洁、开发效率高、支持的模块多,相关的HTTP请求模块和HTML解析模块非常丰富。还有强大的爬虫Scrapy,以及成熟高效的 scrapy-redis分布式策略。 而且,调用其他借口也非常方便(胶水语言)

四、爬虫的整体介绍

-1. 如何抓取HTML页面:
            HTTP请求的处理,urllib、urllib2、requests
            处理后的请求可以模拟浏览器发送请求,获取服务器响应的文件
    -2. 解析服务器响应的内容
            re、xpath、BeautifulSoup4(bs4)、jsonpath、pyquery等
            使用某种描述性一样来给我们需要提取的数据定义一个匹配规则,
            符合这个规则的数据就会被匹配。
    -3. 如何采集动态HTML、验证码的处理
        通用的动态页面采集:Selenium + PhantomJS(无界面):模拟真实浏览器加载js、ajax等非静态页面数据
        Tesseract:机器学习库,机器图像识别系统,可以处理简单的验证码,复杂的验证码可以通过手动输入/专门的打码平台
    -4. Scrapy框架:(Scrapy,Pyspider)
        高定制性高性能(异步网络框架twisted),所以数据下载速度非常快,
        提供了数据存储、数据下载、提取规则等组件。
    -5. 分布式策略 scrapy-reids:
        scrapy-redis,在Scrapy的基础上添加了一套以 Redis 数据库为核心的组件。
            让Scrapy框架支持分布式的功能,主要在Redis里做 请求指纹去重、请求分配、数据临时存储。
    -6. 爬虫 - 反爬虫 - 反反爬虫 之间的斗争:
        其实爬虫做到最后,最头疼的不是复杂的页面,也是晦涩的数据,而是网站另一边的反爬虫人员。

        User-Agent、代理、验证码、动态数据加载、加密数据。

        数据价值,是否值的去费劲做反爬虫。

        1. 机器成本 + 人力成本 > 数据价值,就不反了,一般做到封IP就结束了。
        2. 面子的战争....

        爬虫和反爬虫之间的斗争,最后一定是爬虫获胜!
        为什么?只要是真实用户可以浏览的网页数据,爬虫就一定能爬下来!

五、通用爬虫和聚焦爬虫

1、通用爬虫:搜索引擎用的爬虫系统。

    -1目标:就是尽可能把互联网上所有的网页下载下来,放到本地服务器里形成备份,
            再对这些网页做相关处理(提取关键字、去掉广告),最后提供一个用户检索接口。

    -2抓取流程:
        a) 首选选取一部分已有的URL,把这些URL放到待爬取队列。
        b) 从队列里取出这些URL,然后解析DNS得到主机IP,然后去这个IP对应的服务器里下载HTML页面,保存到搜索引擎的本地服务器。
            之后把这个爬过的URL放入已爬取队列。
        c) 分析这些网页内容,找出网页里其他的URL连接,继续执行第二步,直到爬取条件结束。

    -3 搜索引擎如何获取一个新网站的URL:
        1. 主动向搜索引擎提交网址:http://zhanzhang.baidu.com/linksubmit/url
        2. 在其他网站里设置网站的外链。
        3. 搜索引擎会和DNS服务商进行合作,可以快速收录新的网站。

        DNS:就是把域名解析成IP的一种技术。

    -4 通用爬虫并不是万物皆可爬,它也需要遵守规则:
    Robots协议:协议会指明通用爬虫可以爬取网页的权限。
    Robots.txt 只是一个建议。并不是所有爬虫都遵守,一般只有大型的搜索引擎爬虫才会遵守。咱们个人写的爬虫,就不管了。

    -5 通用爬虫工作流程:爬取网页 - 存储数据 - 内容处理 - 提供检索/排名服务

    -6 搜索引擎排名:
        1. PageRank值:根据网站的流量(点击量/浏览量/人气)统计,流量越高,网站也越值钱,排名越靠前。
        2. 竞价排名:谁给钱多,谁排名就高。

    -7 通用爬虫的缺点:
        1. 只能提供和文本相关的内容(HTML、Word、PDF)等等,但是不能提供多媒体文件(音乐、图片、视频)和二进制文件(程序、脚本)等等。
        2. 提供的结果千篇一律,不能针对不同背景领域的人提供不同的搜索结果。
        3. 不能理解人类语义上的检索。

2、为了解决这个问题,聚焦爬虫出现了:

    聚焦爬虫:爬虫程序员写的针对某种内容的爬虫。
    面向主题爬虫,面向需求爬虫:会针对某种特定的内容去爬取信息,而且会保证信息和需求尽可能相关。

 

 ###################################################################

六、urllib库

  1、简介
          urllib库是Python提供的用于操作URL的模块,在2版本中,有urllib和urllib2两个库,在3版本中,只有urllib库,我们使用3系列。

  2、方法和使用
       urlllib.request 可以用来发送request和获取request的结果
          rullib.parse用来解析和处理URL

1.urllib.request.urlopen方法 
    urlopen(url,data=None,context=None)
    如果没有data则表示post请求。。。如果有则表示get请求
    context表示的是https请求小区ssl错误。
    如有有ssl错误,也可以使用以下代码解决:
        import ssl
        ssl._create_default_https_context = ssl._create_unverified_context

2.urllib.request.urlretrieve(url,file_path)
    将url内容直接下载到file_path中。(一般是整个页面)

3.urllib.parse相关使用
    a)urllib.parse.urlencode()      #post方法
        通过post提交的数据,都需要通过这个函数转码,并且发送请求的时候必须为字节格式。
        使用例子:
            data:是一个字典
            rullib.parse.urlencode(data).encode('utf-8')
    b)urllib.parse.quote()          #get方法  编码
        get参数中,有中文的,需要使用这个函数转码
        使用例子:
            http://www.baidu.com?name=中国
    c)urllib.parse.unquote()        #get方法  解码

   3、HTTPResponse对象常见方法

1.read()    #读取的是二进制数据
    编码  encode()    字符串 --> 字节
    解码  decode()    字节   --> 字符串

2.readline()    #读取一行
  readlines()   #读取全部,返回一个列表
  
##1和2中方法,读取的都是字节类型,需要通过解码转化成字符串类型

3.getcode()     #状态码
  geturl()      #获取url
  getheaders()  #响应头信息。列表里面有元组
  status属性    #http状态码

   4、例题

 1 import urllib.request
 2 
 3 url = "http://www.baidu.com"
 4 # url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1532350126542&di=0b40d417ccdf5e360bec2879ea44caea&imgtype=0&src=http%3A%2F%2Fs3.sinaimg.cn%2Fmw690%2F006LDoUHzy7auXtCqn8c2%26690"
 5 # url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1532350126542&di=0b40d417ccdf5e360bec2879ea44caea&imgtype=0&src=http%3A%2F%2Fs3.sinaimg.cn%2Fmw690%2F006LDoUHzy7auXtCqn8c2%26690"
 6 # url = "https://www.365yg.com/a6579403582011867652/#mid=1582214612406285"
 7 # url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1532363886029&di=bca0c1ae84babe8d1fa0d53c705c436e&imgtype=0&src=http%3A%2F%2Fr2.ykimg.com%2F05410508528FB37D6A0A4D4BF768EB12"
 8 
 9 # 发送请求(url表示要请求的地址)
10 res = urllib.request.urlopen(url=url)
11 
12 print(res,type(res))        #获取res
13 print(res.geturl())         #获取url
14 print(res.getheaders())     #获取请求头信息
15 print(res.status)           #获取状态码
16 
17 #将url内容直接下载到当前目录的filename文件中。
18 urllib.request.urlretrieve(url=url,filename="nice2.jpg")
19 urllib.request.urlretrieve(url=url,filename="baidu.html")
20 
21 #在进行get提交时,如果有rul中有中文,使用quote进行编码
22 str = urllib.parse.quote("https://www.baidu.com/s?ie=utf-8&wd=日本")
23 print(str)
24 
25 #在进行get提交时,可以使用unquote进行解码
26 str1 = urllib.parse.unquote("https%3A//www.baidu.com/s%3Fie%3Dutf-8%26wd%3D%E6%97%A5%E6%9C%AC")
27 print(str1)
例题1
 1 import urllib.request
 2 
 3 url = "http://www.baidu.com"
 4 headers ={
 5     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
 6 }
 7 
 8 #构建高级请求对象的第一种方式
 9 # req=urllib.request.Request(url=url,headers=headers)
10 ##构建高级请求对象的第二种方式-通过懒加载
11 req=urllib.request.Request(url=url)
12 req.add_header("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36")
13 
14 #发送请求
15 res=urllib.request.urlopen(req)
16 print(res)
17 #解码,将二进制字节转成字符串
18 print(res.read().decode("utf-8"))
例题2
 1 import urllib.parse
 2 import urllib.request
 3 
 4 wd = input('请输入您要查询的词语:')
 5 #编码 get请求
 6 wd = urllib.parse.quote(wd)
 7 url = "https://www.baidu.com/s?wd="+wd
 8 # print(url)
 9 # exit()
10 
11 headers = {
12     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
13 }
14 #构建请求对象
15 req = urllib.request.Request(url=url,headers=headers)
16 #发送请求
17 res = urllib.request.urlopen(req)
18 
19 #保存|写入文件
20 with open('china.html','wb') as fw:
21     fw.write(res.read())
22 
23 # with open('Japan.html','w',encoding='utf-8') as fw:
24 #     fw.write(res.read().decode("utf-8"))        
例题3
 1 import urllib.request
 2 import urllib.parse
 3 from lxml import etree
 4 
 5 #解决ssl报错
 6 import ssl
 7 ssl._create_default_https_context = ssl._create_unverified_context
 8 
 9 def loadPage(url):
10     headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1 Trident/5.0;"}
11     request = urllib.request.Request(url, headers = headers)
12     html = urllib.request.urlopen(request).read()
13 
14     #解析HTML文档为HTML_DOM模型
15     content = etree.HTML(html)
16     #返回所有匹配成功的列表集合
17     link_list = content.xpath('//li[@class=" j_thread_list clearfix"]//div[@class="threadlist_title pull_left j_th_tit "]/a/@href')
18     print(link_list,len(link_list))
19 
20     for link in link_list:
21         fulllink = "http://tieba.baidu.com" + link      #每个帖子的链接
22         loadImage(fulllink)
23 
24 #取出每个帖子中每个图片的的链接
25 def loadImage(link):
26     headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1 Trident/5.0;"}
27     request = urllib.request.Request(link, headers=headers)
28     html = urllib.request.urlopen(request).read()
29     content = etree.HTML(html)
30 
31     #返回帖子里所有图片链接的列表集合
32     link_list = content.xpath('//img[@class="BDE_Image"]/@src')
33     for link in link_list:
34         filename = link[-15:]
35         urllib.request.urlretrieve(link,'./tieba/'+filename)
36         print("下载成功"+'----'+filename)
37 
38 
39 def tiebaSpider(url, beginPage, endPage):
40 
41     for page in range(beginPage, endPage + 1):
42         pn = (page - 1) * 50
43         fullurl = url + "&pn=" + str(pn)
44         loadPage(fullurl)
45 
46 
47 if __name__ == "__main__":
48     kw = input("请输入要爬取的贴吧名:")
49     startPage = int(input("请输入起始页:"))
50     endPage = int(input("请输入结束页:"))
51 
52     url = "https://tieba.baidu.com/f?"
53 
54     # 可以使用urlencode({'kw':kw})  --->  https://tieba.baidu.com/f?kw=美女
55     key = urllib.parse.urlencode({"kw": kw})
56     fullurl = url + key
57     # fullurl = url + 'kw=' +kw
58     # print(fullurl)
59 
60     tiebaSpider(fullurl, startPage, endPage)
爬虫百度贴吧图片

 

 

七、POST请求 和 GET请求格式

   1、POST请求

import urllib.parse
import urllib.request

url = "http://fanyi.baidu.com/sug"
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
kw =input('请输入你要查询的词:')

data = {
    'kw':kw
}

#编码动作
data =urllib.parse.urlencode(data).encode('utf-8')
#构建请求对象
req=urllib.request.Request(url=url,headers=headers,data=data)
#发送请求
res=urllib.request.urlopen(req)
#读取响应数据
result=res.read().decode('utf-8')

#写入文本
with open('bdfy.json','w',encoding='utf-8') as fw:
    fw.write(result)

   2、GET请求

import urllib.parse
import urllib.request

url="https://movie.douban.com/top250?"
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}

page =int(input('请输入你要查看的页码:'))
start = (page-1)*25
filter= None

data ={
   'start':start,
   'filter':filter
}
data =urllib.parse.urlencode(data)
url = url+data

#构建请求对象
req=urllib.request.Request(url=url,headers=headers)
#发送请求
res=urllib.request.urlopen(req)

#将整个网页写入文档中
with open('douban.html','w' ,encoding='utf-8') as fw:
    fw.write(res.read().decode('utf-8'))

   3、例题:复杂的get请求--封装函数

 1 import os
 2 import urllib.parse
 3 import urllib.request
 4 #写数据
 5 def download(req,page):
 6     #发送请求
 7     res=urllib.request.urlopen(req)
 8     dirname ='./tieba'
 9     filename =""+str(page)+".html"
10     filepath = os.path.join(dirname,filename)
11     with open(filepath,'wb')  as fw:
12         fw.write(res.read())
13 
14 #拼接url,构建请求对象
15 def build_url(url,page,ba_name):
16     #拼接pn
17     pn =(page-1)*50
18     data ={
19         'kw': ba_name,
20         'pn': pn
21     }
22     #编码
23     data=urllib.parse.urlencode(data)
24     url += data
25     #获取请求对象
26     req = urllib.request.Request(url=url)
27     return  req
28 
29 def main():
30     start_url = int(input('请输入起始页码:'))
31     end_url = int(input('请输入结束页码:'))
32     ba_name = input('请输入贴吧名:')
33     url = 'http://tieba.baidu.com/f?ie=utf-8&'
34     for page in range(start_url,end_url+1):
35         req = build_url(url,page,ba_name)       # 构建完成的url
36         download(req,page)                      # 根据url下载数据
37 
38 if __name__ == "__main__":
39     main()
get请求-封装函数

 

 八、异常处理HTTPerror和URLerror

   HTTPError类是URLError类的子类。。。通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try-except进行捕获异常,异常有两类,URLError\HTTPError。

#异常处理代码
import urllib.request
import urllib.error

url = 'https://blog.csdn.net/whd526/article/details/52279108'
headers={
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
req =urllib.request.Request(url=url,headers=headers)

#在发送请求时候,进行异常处理
try:
    res=urllib.request.urlopen(req)
    print(res.read().decode('utf-8'))

except urllib.error.HTTPError as e:     #HTTPError异常
    print('httperror')
    print(e)
    print(e.code)

except urllib.error.URLError as e:      #URLError异常
    print('URLerror')
    print(e)
    print(e.code)

except Exception as e:                  #所有异常
    print('Exception')
    print(e)
    print(e.code)

print("程序结束")

 九、Handler处理器

    1、简单实用(不使用代理)
        1.之前的urllib.requese.urlopen() 不能构建请求头
        2.urllib.request.Request(url=url, headers=headers),
            高级之处可以定制请求头,但是不能携带cookie,不能使用代理。因此有Handler方法
   
        3.使用个步骤
            a、使用Handler处理器创建对象
            b、使用urllib.request.bulid_opener()方法使用处理器对象。
                创建自定义opener对象
            c、使用自定义opener对象,调用open()方法发送请求。

  4.例题

 1 import urllib.request
 2 
 3 url = "http://www.baidu.com"
 4 headers = {
 5     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
 6 }
 7 
 8 #构建一个Handler对象
 9 handler=urllib.request.HTTPHandler()
10 #通过Handler对象构建一个opener对象
11 opener=urllib.request.build_opener(handler)
12 
13 #构建请求对象
14 req=urllib.request.Request(url=url,headers=headers)
15 #发送请求
16 res=opener.open(req)
17 print(res.read().decode('utf-8'))            
handler简单使用

   2、高级使用(使用代理)

         1.代理服务器
            http://www.kuaidaili.com/   快代理(免费)
       http://www.xicidaili.com/   西刺代理(免费)
        2.本地浏览器配置代理步骤[简单验证]
            设置--高级--打开代理设置--链接--局域网设置--代理服务器--选中为LAN配置、跳过xxx--将代理服务器的地址和端口号写入--保存即可--百度访问ip--查看ip地址
        3.代码配置代理
            访问网址是http,用http代理服务器。访问https,用https代理服务器

   4.例题

 1 import urllib.request
 2 
 3 url = 'https://www.baidu.com/s?ie=utf-8&wd=ip'
 4 headers = {
 5     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
 6 }
 7 
 8 #构建请求对象
 9 req=urllib.request.Request(url=url,headers=headers)
10 #配置代理
11 handler=urllib.request.ProxyHandler({'https':'113.200.56.13:8010'})
12 #构建一个opener对象
13 opener=urllib.request.build_opener(handler)
14 #发送请求
15 res=opener.open(req)
16 
17 with open('ip-daili.html','wb') as fw:
18     fw.write(res.read())
handler代理使用

十、cookielib库 和 HTTPCookieProcessor处理器

         cookielib模块:主要作用是提供用于存储cookie的对象
         HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象

 1 import http.cookiejar
 2 import urllib.request
 3 import urllib.parse
 4 
 5 url = 'https://passport.weibo.cn/signin/login'
 6 headers ={
 7     'Host': 'passport.weibo.cn',
 8     'Connection': 'keep-alive',
 9     'Origin': 'https://passport.weibo.cn',
10     'Content-Type': 'application/x-www-form-urlencoded',
11     'Cookie':' _T_WM=d75ad87c2e45218a11a9193631f6aedc; login=903b2dfe558d757c50a86dbd7d018964',
12     'Referer': 'https://passport.weibo.cn/signin/login?entry=mweibo&r=http%3A%2F%2Fweibo.cn%2F&backTitle=%CE%A2%B2%A9&vt=',
13     'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
14 }
15 data = {
16     'username':'18813145908',
17     'password':'201999gD',
18     'savestate':'1',
19     'r':'http%3A%2F%2Fweibo.cn%2F',
20     'ec':'0',
21     'entry':'mweibo',
22     'wentry':'',
23     'loginfrom':'',
24     'client_id':'',
25     'code':'',
26     'qq':'',
27     'mainpageflag':'1',
28     'vid':'cec4edb660611bdd0060e977a2c89479287a2c894792',
29     'hff':'',
30     'hfp':''
31 }
32 
33 #创建一个OOKIEJAR对象
34 cookie=http.cookiejar.CookieJar()
35 #通过HTTPCookieProcessor创建Handler对象
36 handler=urllib.request.HTTPCookieProcessor(cookie)
37 #通过Handler对象构建一个opener对象
38 opener=urllib.request.build_opener(handler)
39 #编码
40 data = urllib.parse.urlencode(data).encode('utf-8')
41 #构建请求对象
42 req=urllib.request.Request(url=url,headers=headers,data=data)
43 #发送请求
44 res=opener.open(req)
45 
46 # with open('weibo.html','wb') as fw:
47 #     fw.write(res.read())
48 
49 print(res.read().decode('gbk'))
50 
51 url1 = 'https://weibo.cn/3386230482/info'
52 
53 headers1 ={
54     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
55 }
56 
57 req1=urllib.request.Request(url=url1,headers=headers1)
58 res1=opener.open(req1)
59 
60 print(res1.read().decode('gbk'))
View Code

十一、正则在爬虫的使用

       1、正则原理
          find、rfind、replace
              字符串处理函数只能处理固定的字符串 baby  hello
              不能处理一类字符串,通过正则表达式来进行处理
            正则规则:
                    单字符:. [abc]  \d  \D  \w  \W  \s  \S
                    数量修饰: *  +  ?  {m}  {m,}  {m,n}
                    边界修饰 ^  $  \b(词边界)  \B(非词边界)
                    子模式  (.*)     
         贪婪模式
                    <div>呵呵<div>哈哈</div>嘿嘿</div>
                        '<div>.*</div>'
                    懒惰匹配 .*?  .+? 
                    修饰模式
                        re.S   单行模式  re.M   多行模式  re.I   忽略大小写

   2、例题

import re

str1 = '<div>哈哈</div><div>呵呵</div><div>嘿嘿</div>'
#贪婪模式
# res1 = re.match('<div>.*</div>',str1)
#懒惰模式
res1 = re.match('<div>.*?</div>',str1)
print(res1)

#子模式
str2 = 'goodgood678study789'
res2 = re.match('(good)(good)(\d+)study(\d+)',str2)

print(res2.group())             # group()和group(0) 结果一样,索引从1开始
print(res2.group(0))            # 这两个结果一样:goodgood678study789

print(res2.group(1))            # 结果为第一个good
print(res2.group(2))            # 结果为第二个good
print(res2.group(3))            # 结果为:678
print(res2.group(4))            # 结果为:789

#单行多行模式
# re.S   单行模式  re.M   多行模式  re.I   忽略大小写
str3 ='''good good study day dayup
good good study day dayup 
nice to meet you 
happy every day  '''

res3 = re.compile('^good',re.S)
result3 = res3.search(str3)
print(result3)

res4 = re.compile('^good',re.M)
result4 = res4.findall(str3)
print(result4)

 十二、Xpath、lxml和xml

     1、XML(EXtensible Markup Language),可扩展标记语言。   
         ##XML的节点关系
            <?xml version="1.0" encoding="utf-8"?>
            <bookstore>
            <book>
                 <title>Harry Potter</title>
                 <author>J K. Rowling</author>
                 <year>2005</year>
                 <price>29.99</price>
            </book>
            </bookstore>    
          1.父节点:每个元素以及属性都有一个父节点。。。    book 元素是 title、author、year 以及 price 元素的父
          2.子节点:元素节点可有零个、一个或多个子节点。。。title、author、year 以及 price 元素都是 book 元素的子
          3.同胞:拥有相同的父节点。。。                    title、author、year 以及 price 元素都是同胞
          4.先辈:某节点的父、父的父。。。                  title 元素的先辈是 book 元素和 bookstore 元素
          5.后代:某节点的子、子的子。。。                  bookstore 的后代是 book、title、author、year 以及 price 元素

    2、XPath
          1.基本知识
              XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。
              W3School官方文档:http://www.w3school.com.cn/xpath/index.asp
          2.选取节点
              a) nodename:选取次节点中的所有子节点
                  bookstore   #表示选取bookstore元素的所有子节点
           
              b) /:从跟节点选取
                  /bookstore  #选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
                  bookstore/book  #选取属于bookstore的子元素的所有book元素
               
              c) //: 从匹配选择的当前节点选取文档中的节点,不考虑他们的位置
                  //book      #选取所有book子元素,不管他们的位置
                  bookstore//book #选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
                  //@lang     #选取名为lang的所有属性                             
              d) . : 选取当前节点            
              e) .. :选取当前节点的父节点           
              f) @ :选取属性

           3.谓语(predicates)
              谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中
             ###常用示例
                a)bookstore/book[1]               #选取属于 bookstore 子元素的第一个 book 元素。
                b)bookstore/book[last()]          #选取属于 bookstore 子元素的最后一个 book 元素。
                c)bookstore/book[last()-1]        #选取属于 bookstore 子元素的倒数第二个 book 元素。
                d)bookstore/book[positon<3]       #选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
           
                e)//title[@lang]                     #选取所有拥有名为 lang 的属性的 title 元素。
                f)//title[@lang=’eng’]               #选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
                g)/bookstore/book[price>35.00]     #选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
                h)/bookstore/book[price>35.00]/title   #选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

    4.选取未知节点
              a) * :匹配任何元素节点
                  /bookstore/* #选取 bookstore 元素的所有子元素。
              b) @*:匹配任何属性节点
                  //*             #选取文档中的所有元素。
              c) node:匹配任何类型的节点
                  //title[@*]     #选取所有带有属性的 title 元素 

    5.选取若干路径
              通过在路径表达式中使用“|”运算符,您可以选取若干个路径

              //book/title | //book/price           #选取 book 元素的所有 title 和 price 元素。
              //title | //price                     #选取文档中的所有 title 和 price 元素。
              /bookstore/book/title | //price     #选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。     

          6.其他获取节点方法
              属性定位:根据属性查找标签
              层级定位:一级一级查找
              索引定位:下标从1开始
           
              查找id是maincontent的div下面的h1节点
                  //div[@id="maincontent"]/h1
                  //div[@class="head_wrapper"]/div[@id="u"]/a[1]
              逻辑运算 //div[@id="head" and @class="s_down"]
              模糊匹配
                  查找所有的div,id中有he的div
                  //div[contains(@id, "he")]
                  查找所有的div,id中以he开头的div
                  //div[starts-with(@id, "he")]
                  查找所有的div,id中以he结尾的div
                  //div[ends-with(@id, "he")]
              取文本
                  //div[@class="head_wrapper"]/div[@id="u"]/a[1]/text()
                  //div[@class="head_wrapper"]/div[@id="u"]/a[1]
                  obj.text   将内容获取到
              取属性
                  //div[@class="head_wrapper"]/div[@id="u"]/a[1]/@href 

          7.程序中使用xpath方法
              from lxml import etree
              d_etree = etree.parse('本地html')    
              d_etree = etree.HTML('网上html字符串(也可以是字节类型)')
              d_etree.xpath('xpath路径') 返回的是一个列表
              获取到节点对象之后obj obj.xpath('xpath路径') 

 1 #文档内容
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8" />
 5     <title>xpath测试页面</title>
 6 </head>
 7 <body>
 8     <ol>
 9         <li class="haha">醉卧沙场君莫笑,古来征战几人回</li>
10         <li class="heihei">两岸猿声啼不住,轻舟已过万重山</li>
11         <li id="hehe" class="nene">一骑红尘妃子笑,无人知是荔枝来</li>
12         <li class="xixi">停车坐爱枫林晚,霜叶红于二月花</li>
13         <li class="lala">商女不知亡国恨,隔江犹唱后庭花</li>
14     </ol>
15     <div id="pp">
16         <div>
17             <a href="http://www.baidu.com">李白</a>
18         </div>
19         <ol>
20             <li class="huanghe">君不见黄河之水天上来,奔流到海不复回</li>
21             <li id="tata" class="hehe">李白乘舟将欲行,忽闻岸上踏歌声</li>
22             <li class="tanshui">桃花潭水深千尺,不及汪伦送我情</li>
23         </ol>
24         <div class="hh">
25             <a href="http://mi.com">雷军</a>
26         </div>
27         <ol>
28             <li class="dudu">nice to meet you</li>
29             <li class="meme">hao do you do</li>
30         </ol>
31     </div>
32 </body>
33 </html>
例题:本地文档
 1 from lxml import etree
 2 #构建document对象
 3 e_tree=etree.parse('testXpath.html')
 4 # print(e_tree)
 5 #1-获取所有的li节点
 6 res=e_tree.xpath('//li')
 7 
 8 #2-获取所有li节点的class属性
 9 res=e_tree.xpath('//li/@class')
10 
11 #3-获取每一个ol节点最后一个li节点的文本内容
12 res=e_tree.xpath('//ol/li[last()]/text()')
13 
14 #4-拿到http://mi.com值
15 res=e_tree.xpath('//div[@class="hh"]/a/@href')[0]
16 
17 #5-拿到雷军文本值
18 res=e_tree.xpath('//div[@class="hh"]/a/text()')[0]
19 
20 #6-找到第2个ol节点里面class以h开头的li节点
21 res=e_tree.xpath('//div[@id="pp"]/ol/li[starts-with(@class,"h")]/text()')
22 
23 #7-找到第2个ol节点里面class以h开头的第2个li节点文本
24 res=e_tree.xpath('//div[@id="pp"]/ol/li[starts-with(@class,"h")]/text()')[1]
25 print(res)    
使用xpath获取本地文档信息
 1 import os
 2 import urllib.request
 3 from lxml import etree
 4 
 5 def download_img(url_list, name_list):
 6     print('进入download')
 7     dirpath = "./imgs"
 8     for i in range(len(name_list)):
 9         #获取图片后缀名
10         suffix = os.path.splitext(url_list[i])
11         print(suffix)
12         suffix = suffix[-1]
13 
14         #拼接图片全路径
15         file_path = os.path.join(dirpath,name_list[i])+suffix
16         try:
17             urllib.request.urlretrieve(url_list[i],file_path)
18             print("%s-下载成功" % file_path)
19         except Exception as e:
20             print("%s-下载失败" % file_path)
21 
22 def get_data(req):
23     print('进入get—data')
24     #发送请求
25     res = urllib.request.urlopen(req)
26     #读取响应内容,获取整个网页内容
27     html = res.read().decode('utf-8')
28     #构建document对象
29     doc_etree = etree.HTML(html)
30     #找到所有图片的url
31     url_list = doc_etree.xpath('//div[@id="container"]/div/div/a/img/@src2')        #最好查看源码获取src还是src2
32     name_list = doc_etree.xpath('//div[@id="container"]/div/div/a/img/@alt')
33 
34     #下载图片
35     download_img(url_list,name_list)
36 
37 def bulid_req(url):
38     print("进入bulid_req")
39     headers = {
40         'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
41     }
42     req = urllib.request.Request(url=url,headers=headers)
43     return req
44 
45 def main():
46     start_page = int(input('开始页码:'))
47     end_page = int(input('结束页码:'))
48     url_temp = 'http://sc.chinaz.com/tupian/meinvtupian'
49     print('正在给你下载啊。。。骚年')
50     for page in range(start_page,end_page+1):
51         if page != 1:
52             url = url_temp + "_" + str(page) + ".html"
53         else:
54             url = url_temp
55         print(url)
56         #构建一个请求对象
57         req = bulid_req(url)
58         get_data(req)
59 
60 if __name__ == "__main__":
61     main()
使用xpath从网站下载文件
 1 #糗事百科实战
 2 import json
 3 import urllib.request
 4 from lxml import etree
 5 
 6 def build_url(url):
 7     headers={
 8         'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
 9     }
10     req=urllib.request.Request(url=url,headers=headers)
11     return req
12 
13 def get_data(req):
14     res=urllib.request.urlopen(req)
15     doc = res.read().decode('utf-8')
16     doc_html =etree.HTML(doc)
17     div_list=doc_html.xpath('//div[@id="content-left"]//div[starts-with(@class,"author")]')
18     # print(len(div_list))
19     # print(div_list)
20     # print(type(div_list))
21     items = []
22     for div in div_list:
23         item = {}
24         img_temp_url = div.xpath('./a/img/@src')[0]
25         img_url ='https:'+img_temp_url
26         name_tmp =div.xpath('./a/h2/text()')[0]
27         name = name_tmp.strip('\n')
28         # print(name)
29         # exit()
30         item['img_url'] = img_url
31         item['name'] = name
32         items.append(item)
33     str=json.dumps(items,ensure_ascii=False)
34     with open('qiushi.json','w',encoding='utf-8') as fw:
35         fw.write(str)
36 
37 def main():
38     url = 'https://www.qiushibaike.com/text/'
39     req=build_url(url)
40     get_data(req)
41 
42 if __name__ == "__main__":
43     main()
使用xpath获取糗事百科

十三、bs4(BeautifulSoup4)

1、bs4解析器
    1.概述:
        lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,
        因此时间和内存开销都会大很多,所以性能要低于lxml。

        BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,
        支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
    2.使用方法
        from bs4 import BeautifulSoup
        # 本地文件生成对象
            soup = BeautifulSoup(open('bs4_test.html'), 'lxml') 
        # 网上文件生成对象
            soup = BeautifulSoup('网上下载的字符串', 'lxml')

2、四大对象种类
    Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,
    所有对象可以归纳为:Tag、NavigableString、BeautifulSoup、Comment
    1.Tag通俗点讲就是HTML中的每一个标签
        例如: title、head、a、p等等 HTML 标签加上里面包括的内容就是 Tag
            <head><title>The Dormouse's story</title></head>
            <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
            <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
       
        例子:
            html = """
            <html><head><title>The Dormouse's story</title></head>
            <body>
            <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
            <p class="story">Once upon a time there were three little sisters; and their names were
                <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
                <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
                <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
                and they lived at the bottom of a well.
            </p>
            <p class="story">...</p>
            """            
            
            from bs4 import BeautifulSoup
            
            #创建 Beautiful Soup 对象
            soup = BeautifulSoup(html)

            print(soup.title)         #获取title的tag    # <title>The Dormouse's story</title>
            print(soup.head)          #获取head的tag     # <head><title>The Dormouse's story</title></head>
            print(soup.a)             #获取a的tag        # <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
            print(soup.p)             #获取p的tag        # <p class="title" name="dromouse"><b>The Dormouse's story</b></p>

        我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。
        但是注意,它查找的是在所有内容中的第一个符合要求的标签

        # 对于Tag有两个重要属性,name和attrs
            print(soup.name)    #获取标签名
            # [document]        #soup 对象本身比较特殊,它的 name 即为 [document]

            print(soup.head.name)
            # head              #对于其他内部标签,输出的值便为标签本身的名称

            print(soup.p.attrs)  #获取p标签的attrs,将属性作为字典返回
            # {'class': 'title', 'name': 'dromouse'}

            # 获取节点属性值的3中方法(字典取值):
                obj.attrs.get('title')	    obj.get('title')	 obj['title']
            
            print(soup.p['class']) #等效于     print(soup.p.get('class'))
            # ['title']            #还可以利用get方法,传入属性的名称,二者是等价的

            soup.p['class'] = "newClass"
            print(soup.p)        # 可以对这些属性和内容等等进行修改
            # <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>

            del soup.p['class'] # 还可以对这个属性进行删除
            print(soup.p)
            # <p name="dromouse"><b>The Dormouse's story</b></p>                
    
    2. NavigableString(获取标签内容)
        obj.string  和   obj.get_text()
        # 如果内容中有注释,string会获取到注释的内容,get_text()获取不到注释内容,但可以获取非注释内容
        # 如果内容中有标签,string返回None,get_text()返回文本内容。
        
        print(soup.p.string)        # The Dormouse's story

    3. BeautifulSoup  对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag
    
    4. Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
        print(soup.a)
        # <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>

        print(soup.a.string)
        # Elsie 

3、遍历文档树
    1.直接子节点 :.contents .children 属性
        .contents:可以将tag的子节点以列表的方式输出
            print(soup.head.contents)       #[<title>The Dormouse's story</title>]
            print(soup.head.contents[0])    #<title>The Dormouse's story</title>
        .childern: 它返回的不是列表而是一个list生成器,可以通过遍历获取所有子节点。 
            print(soup.head.children)       #<listiterator object at 0x7f71457f5710>

            for child in soup.body.children:
                print(child)                #输出的内容为body标签中的所有标签                

    2.所有的子孙节点:.descendants 属性
        .contents 和 .children 属性仅包含tag的直接子节点,
        .descendants 属性可以对所有tag的子孙节点进行递归循环,和 children类似,我们也需要遍历获取其中的内容。

        for child in soup.descendants:
            print(child)        #输出结果为所有的html中的标签。并且递归循环,一层一层进行输出

4、搜索文档树
    1.find  #返回第一个对象
      find('a')                 #返回第一个a标签
      find('a', title='xxx')    #返回第一个a标签,并且其title='xxx'  	
      find('a', class_='xxx')   #返回第一个a标签,并且其class='xxx'

    2.find_all(name, attrs, recursive, text, **kwargs)
      1)传字符串
        print(soup.find_all('b'))      #获取所有的b标签
            # [<b>The Dormouse's story</b>]
        print(soup.find_all('a'))      #获取所有a标签
            # [<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, 
            #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, 
            #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]]

      2)传正则表达式 (通过正则表达式的 match() 来匹配内容)
        #获取所有以b开头的标签
            import re
            for tag in soup.find_all(re.compile("^b")):
                print(tag.name)
            # body
            # b
      3)传列表 (获取列表中的每个标签)
        #获取a标签和b标签
            print(soup.find_all(["a", "b"]))
                # [<b>The Dormouse's story</b>,
                #  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
                #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
                #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
            print(soup.find_all(['a',limit=2]))
                #获取所有a标签中的前两个
      
      4)通过id获取
            print(soup.find_all(id='link2'))    #获取id='link2'的标签,并以列表返回
                # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
      5)通过text获取
            通过 text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表
            soup.find_all(text="Elsie")
            # [u'Elsie']

            soup.find_all(text=["Tillie", "Elsie", "Lacie"])
            # [u'Elsie', u'Lacie', u'Tillie']

            soup.find_all(text=re.compile("Dormouse"))
            [u"The Dormouse's story", u"The Dormouse's story"]

    3.通过选择器获取
        a、标签名不加任何修饰,类名前加.  id名前加#
        b、在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select(),返回类型是 list    
      1)通过标签名查找
            print(soup.select('title')) 
                #[<title>The Dormouse's story</title>]
      2)通过类名查找
            print(soup.select('.sister'))
                #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, 
                # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, 
                # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      3)通过id查找
            print(soup.select('#link1'))
                #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
      4)组合查找
            组合查找即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的,例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开。           
            
            标签名 .类名   #id名 .类名
            标签名 > .类名 > #id名

            print(soup.select('p #link1'))  #p标签 的子孙中 id=link1的
            #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

            print(soup.select("head > title"))  #head标签下的title标签
            #[<title>The Dormouse's story</title>]
      5)属性查找
            查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。
            print(soup.select('a[class="sister"]'))
            #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

            print(soup.select('a[href="http://example.com/elsie"]'))
            #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
            
            同样,属性仍然可以与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格
            print(soup.select('p a[href="http://example.com/elsie"]'))
            #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

 

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>soup测试</title>
 6 </head>
 7 <body>
 8     <div class="tang">
 9         <ul>
10             <li><a href="http://www.baidu.com" title="出塞">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
11             <li><a href="http://www.163.com" class="taohua">人面不知何处去,桃花依旧笑春风</a></li>
12             <li><a href="http://mi.com" id="hong">去年今日此门中,人面桃花相映红</a></li>
13             <li><a href="http://qq.com" class="taohua">故人西辞黄鹤楼,烟花三月下扬州</a></li>
14         </ul>
15     </div>
16     <div id="meng">
17         <p class="jiang">
18             <span>三国猛将</span>
19             <ol>
20                 <li>关羽</li>
21                 <li>张飞</li>
22                 <li>赵云</li>
23                 <li>马超</li>
24                 <li>黄忠</li>
25             </ol>
26             <div class="cao">
27                 <ul>
28                     <li>典韦</li>
29                     <li>许褚</li>
30                     <li>张辽</li>
31                     <li>张郃</li>
32                     <li>于禁</li>
33                     <li>夏侯惇</li>
34                 </ul>
35             </div>
36         </p>
37     </div>
38 </body>
39 </html>            
bs4本地文件信息
 1 import bs4
 2 from bs4 import BeautifulSoup
 3 
 4 # 创建bs4对象
 5 bs=BeautifulSoup(open('1-bs4_test.html'),'lxml')
 6 # 找到a标签和title
 7 tag_a=bs.a
 8 print(tag_a)
 9 print(type(tag_a))
10 print(bs.title)
11 # 点属性attrs
12 print(tag_a.attrs)
13 print(tag_a.name)
14 # 获取节点属性值(3种方式)
15 print(tag_a.attrs.get("title"))
16 print(tag_a.get("title"))
17 print(tag_a['title'])
18 # 获取节点内容
19 print(tag_a.string)
20 print('-----------------------')
21 print(tag_a.get_text())
22 # 获取直接子节点
23 print(len(bs.body.contents))
24 # 获取子孙节点
25 print(bs.body.descendants)
26 for tag in bs.body.descendants:
27     print(tag)
28 find find_all select
29     print(bs.find('a'))
30     print(bs.find('a',title="出塞"))
31     print(bs.find('a',id="hong"))
32     print(bs.find('a',class_="taohua"))
33     print(bs.find('a',href="http://qq.com"))
34     
35     print(bs.find_all('a'))
36     print(bs.find_all('a',limit=2))
37     print(bs.find_all(['a','span']))
38 
39 # 根据层级选择器 和属性选择器
40 print(bs.select('div[class="tang"] a[class="taohua"]'))
41 # 获取最后一个内容
42 print(bs.select('div[class="tang"] a[class="taohua"]')[-1].string)
bs4解析本地文件
 1 import json
 2 import urllib.parse
 3 import urllib.request
 4 import bs4
 5 from bs4 import BeautifulSoup
 6 
 7 
 8 class QianChen(object):
 9     def __init__(self,url,gzgw,start_page,end_page):
10         super(QianChen,self).__init__()
11         self.url = url
12         self.gzgw = gzgw
13         self.start_page = start_page
14         self.end_page = end_page
15         self.headers={
16             'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
17         }
18         self.items = []
19 
20     #构建请求对象
21     def build_url(self,page):
22         data ={
23             'gzgw':self.gzgw,
24             'page' :str(page)
25         }
26         url = self.url+urllib.parse.quote(data['gzgw'])+',2,'+data['page']+'.html'
27         req = urllib.request.Request(url=url,headers=self.headers)
28         return req
29 
30     #解析数据
31     def download(self,req):
32         res =urllib.request.urlopen(req)
33         bs = BeautifulSoup(res.read(),'lxml')
34         div_list=bs.select('#resultList .el')[1:]
35         # print(len(div_list))
36         for div in div_list:
37             item = {}
38             gzgw =div.select('p a')[0].get_text()
39             gsmc = div.select('.t2 > a')[0].get_text()
40             gzdd = div.select('.t3')[0].get_text()
41             zwxs = div.select('.t4')[0].get_text()
42             fbrq = div.select('.t5')[0].get_text()
43             item['gzgw'] = gzgw.strip()
44             item['gsmc'] = gsmc
45             item['gzdd'] = gzdd
46             item['zwxs'] = zwxs
47             item['fbrq'] = fbrq
48             self.items.append(item)
49 
50     #对外提供的接口函数
51     def start(self):
52         for page  in range(self.start_page,self.end_page+1):
53             req=self.build_url(page)
54             self.download(req)
55 
56         #写入文件
57         str = json.dumps(self.items,ensure_ascii=False)
58         with open('qcwy.json','w',encoding='utf-8') as fw:
59             fw.write(str)
60 
61 def main():
62     url = "https://search.51job.com/list/010000,000000,0000,00,9,99,"
63     gzgw=input('请输入职位名称:')
64     start_page = int(input('请输入开始页码:'))
65     end_page = int(input('请输入结束页码:'))
66     qc = QianChen(url,gzgw,start_page,end_page)
67     qc.start()
68 
69 if __name__ == "__main__":
70     main()
bs4获取前程无忧信息

 

 

 

 

 

 

#######后续更新

 

posted @ 2018-07-29 23:42  Monomania丶pp  阅读(137)  评论(0)    收藏  举报