Python - 04 - 数据获取/网络请求

165 阅读3分钟

获取网页源代码

  • 使用urlopen函数
        form urllib.request import urlopen 
        url = "http://www.xxx.com"
        resp = urlopen(url)
        with open("xxx.html",mode="w",encoding="utf-8") as f:
        f.write(resp.read().decode("utf-8"))
        //基本都是utf-8或者gbk
    
  • url解析
    from urllib import parse
    url = "http://www.baidu.com/123/333.html"
    img_url = "/111.html"
    new_url = parse.urljoin(url,img_url) # http://www.baidu.com/111.html
    如果img_url以/开头,则urljoin会自动提取url的域名跟img_url拼接
    如果img_url不以/开头,则urljoin会将333.html删除,再将img_url拼接
    

requests库 (是同步的)

  • 安装: pip3 install requests
  • 使用: import requests
    • 设置headers: headers = {'User-Agent':'xxx'},防止反pa
    • get方法:
      • res = requests.get(url,params=params,headers=headers)
      • res.text:拿到页面源代码
      • res.json()
      • res.encoding = 'utf-8':设置字符集
    • post方法:
      • res = requests.post(url,data = data)
      • res.json()
      • res.content: 这个是二进制内容,一般用于图片或视频的下载写入
  • session:用来进行一连串的操作,比如需要cookie的url
    • session = requests.session()
  • 代理: `kuaidaili.com/free/intr/1/
      proxy = {
          "http":"`http://xxx:port`",
          "https":"`https://xxx:port`"
      }
      resp = requests.get(url,proxies=proxy)
    

1.re模块(内置模块),用来提取分析数据的

  • findall(Regular:正则,要匹配的字符串)

    import re
    result = re.findall(r'\d+',"123")
    备注: 正则前加r,就可以不用关心里面的转义问题
    
  • finditer:返回迭代器,效率比findall高

    result = finditer(r"\d+","1233哈333")
    for item in result:
        print(item.group()) #从匹配的结果中拿到数据
    
    
  • search: 只匹配第一次的匹配到的内容

  • match: 从字符串开头开始匹配

  • compile(正则):预加载,提前把正则对象加载完毕

  • 分组查询

    obj = re.compile(r'<div id='(?P<id>\d+)'>(?P<name>.*?)</div>')
    result = obj.finditer('字符串')
    for item in result:
        id = item.group('id')
        name = item.group('name')
    #?P<名称>正则: 这个是给分组起名字
    
  • ?P<名称>正则: 这个是给分组起名字

  • re.S 可以让.能匹配到换行符

    obj = re.compiler(r"正则",re.S)
    
  • 示例:

    import requests
    import re
    
    url = "https://movie.douban.com/top250"
    
    f = open('doubanMoive.csv',mode='w',encoding='utf-8')
    
    headers = {
        "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "Cookie":''
    }
    
    resp = requests.get(url,headers=headers)
    
    content = resp.text
    
    # re模块
    regular = re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>'
                         r'.*?导演:(?P<dao>.*?)&nbsp;'
                         r'.*?<br>(?P<year>.*?)&nbsp;'
                         r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
                         r'.*?<span>(?P<num>.*?)人评价</span>',
                         re.S)
    
    
    result = regular.finditer(content)
    
    for item in result:
        name = item.group('name')
        dao = item.group('dao')
        year = item.group('year').strip()
        score = item.group('score')
        num = item.group('num')
        f.write(f"电影名:{name},导演:{dao},年份:{year},评分:{score},评价人数:{num}\n")
    
    
    f.close()
    resp.close()
    

2. bs4库

  • 安装: pip3 install bs4
  • 引入: form bs4 import BeautifulSoup
  • 初始化: page = BeautifulSoup(html字符串,"html.parse")
  • 查找一个find: li = page.find("li",attrs={"属性名":"值"})
  • 查找全部find_all
  • 可以继续查找: a = li.find("a"); a.text;a.get("href")

获取数据

  • 如果在获取子页面的href的字符串是以/开头,则用域名直接加上href
  • 如果不是以/开头,则用当前页面的url,去掉当前url的最后一个/后面的内容,再拼接上href
    • 这个可以使用from urllib import parse工具实现, new_url = parse.urljoin(url,src)
  • 下载图片
    img_resp = requests.get(img_url)
    with open('123.png',mode='wb') as f:
        f.write(img_resp.content)
    

3. xpath解析

  • 安装 pip3 install lxml
  • 导入 from lxml import etree 如果报错,则使用 form lxml import html;etree = html.etree
  • 示例
    xml = "xxxxxxx"
    et = etree.XML(xml) 
    result = et.xpath("/app") # /表示根节点
    result = et.xpath("/app/name") #找app下的直接后代name
    result = et.xpath("/app/name/text()") # name中的文本
    result = et.xpath("/app//name") #找app下的子孙后代是name标签的
    result = et.xpath("/app/*/name") #找app下的孙子是name标签的
    result = et.xpath("/app/name[@class='abc']") #找app直接后代是name并且class=abc的
    result = et.xpath("/app/name[2]") #找app直接后代是name标签并且是第2个
    result = et.xpath("/app/name/@id") #拿到app直接后代是name标签的id
    result = li.xpath("./a") #拿到li下的a标签, ./表示当前路径
    

4. pyquery

  • 安装 pip3 install pyquery
  • 导入 from pyquery import PyQuery
  • 使用
    1. p = PyQuery(html)
    2. p(选择器)
    3. p(选择器).items() 当选择的是多个标签的时候,返回迭代器
    4. attr(属性名)
    5. text() 只获取文本或子代文本
    6. html() 获取后代的所有html标签
  • 修改属性
    1. p(选择器).after(PyQuery"<div></div>") #在标签后添加标签,PyQuery加不加都行
    2. p(选择器).append("<div></div>") #在标签内的最后添加标签
    3. p(选择器).attr("class","aaa") #新增/修改属性
    4. p(选择器).remove_attr("") #删除属性
    5. p(选择器).remove() #删除标签
    6. p(选择器:div > dl:nth-child(1) > dd).eq(0).text(): eq是从搜索到的结果集合里取第几个
    7. p(div> dl > dt:contains("有没有这个文字")): contains判断dt里面有没有这个文字