爬虫 | 基本步骤和解析网页的几种方法

爬虫的步骤可以简单的概括为:

  1. 获取网页并拿到HttpResponse对象,一般都是urllib库或者requests库
    # 设置要爬取的网页,以及headers伪装浏览器(最基本防反扒手段)
    url = 'https://example.com'
    headers = {
"User-Agent":"里面的内容在浏览器--network--选择一个html查看Headers -- requests headers -- User-Agent"
}

    # urllib
    import urllib.request
    response = urllib.request.urlopen(url = url, headers = headers)
    response.read()  #>>>> 读取网页内容

    # requests
    import requests
    response = requests.get(url = url, headers = headers)
    response.encoding = 'utf-8' # >>> 指定字符集
    page = response.text  #>>>> 读取网页内容
  1. 解析网页(正则、bs4、xpath)
网页有两种渲染情况,一种是服务器渲染,就比如电影天堂那种,呈现出来的整个页面的数据都是后端一起发来的。另一种是客户端渲染,比如一些动态加载,下滑才读取数据的那种,这种就是第一次请求后服务器发来的是html骨干框架,要向下继续加载继续请求后,服务器才会进一步发送数据,然后浏览器/客户端这边再把数据填入html框架中。所以对于第二种爬取数据时,第一次请求里的信息有时候是没用的,重点在后面的请求

"""正则表达式"""

# 先用compile预加载自定义的正则表达式(这样速度快点)
 entity_regex = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>'
                                  r'.*?<br>(?P<year>.*?)&nbsp'
                                  r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
                                  r'.*?<span>(?P<number>\d+)人评价</span>', flags=re.S)
# 这里必须加re.S,这是为了匹配回车字符。.是匹配除回车之外的所有字符,*表示0及无数次,?表示惰性
        
        # 用迭代器获取,还可以写作re.finditer(entity_regex, page_content)
        entity_iter = entity_regex.finditer(page_content)

# 从迭代器中将各组数据单独提取,则是group,如果直接提取字典,则是groupdict
        for entity in entity_iter:
        # print(entity.group('name'))
        # print(entity.group('year').strip())  # 因为年份前面有空格,所以用strip
        # # print(type(name.group('year').strip()))  # 用.*?匹配到的数字,格式是str字符串
        # print(entity.group('score'))
        # print(entity.group('number'))
        # # print(type(name.group('number')))  # 用\d+匹配到的数字,格式依旧是str字符串,因为正则匹配到的内容都用str返回

            dic = entity.groupdict()
            dic['year'] = dic['year'].strip()  # 单独处理一下year的空白



"""Beautiful Soup"""

# 1.1. 解析主页面源代码
soup = BeautifulSoup(page, 'html.parser')
href_list = soup.find('div', class_ = 'TypeList').find_all('a', class_ = 'TypeBigPics')

# 1.2 提取子页面链接
for href in href_list:
    sub_url = href.get('href')

    # 2. 获得子页面源代码
    sub_html = requests.get(url = sub_url, headers = headers)
    sub_html.encoding = 'utf-8'
    sub_page = sub_html.text

    # 我发现网页有两种图片,一个是gif,一个是jpg,它们的各自子页面格式有所不同

    # 2.1 解析gif子页面,拿到高清图片路径, 由于发现直接用get很难找到一个直接定位的属性,所以用正则了
    regex_pic = re.compile(r"""<img alt=".*?" src="(?P<pic_src>.*?)" /></a></p>""", flags=re.S)
    pic_iter = re.finditer(regex_pic, sub_page)
    for pic in pic_iter:
        pic_src = pic.group('pic_src')
        # print(f"内容是:{pic_src}")

比较re、beautiful soup、xpath

# 正则表达式(re):
擅长从文本中查找和匹配符合特定模式的字符串。如果你需要查找的是简单的文本模式,例如电话号码、邮箱地址等,那么正则表达式会是一个很好的选择。
# BeautifulSoup:
擅长解析HTML和XML文档,并将它们转化为Python可以理解和操作的树形结构(DOM树)。如果你需要定位或提取HTML文档中的标签、属性或文本内容,BeautifulSoup会是一个强大的工具。它支持多种选择器,如标签名、CSS类名、ID等。
# XPath:
同样擅长解析HTML和XML文档,但更侧重于通过路径表达式来定位和提取文档中的元素。XPath提供了非常丰富的路径选择语言,可以精确地指定要查找的元素位置。它常用于处理结构复杂或具有特定模式的文档。XPath经常与lxml库结合使用,因为lxml提供了对XPath表达式的良好支持。
  1. 保存(csv)
  最好是一开始就设置好储存文件路径等,如果不想用with open,那就直接用open+close
"""这里最需要注意的就是处理with open 和 for循环的关系,否则一不留神就容易导致dic的值或者文件被反复覆盖,只剩下最后一点数据"""
  
  # 用with open
    with open('top250.csv', 'w', encoding='utf-8') as f:  # 1) 创建一个文档
      csv_writer = csv.writer(f)                          # 2) 创建一个可写对象
      csv_writer.writerow(dic.values())                   # 3)写入

  # 用open + close
      f = open('top250.csv', 'w', encoding='utf-8')       # 1) 创建一个文档
      csv_writer = csv.writer(f)                          # 2) 创建一个可写对象
      csv_writer.writerow(dic.values())                   # 3)写入
      f.close()                                           # 4) 关闭文件
  1. 关闭响应
   response.close() 
'''别忘了!'''
# 但实际上对于单个的requests.get请求,通常不需要手动关闭连接,因为requests库会自动为你处理。但在某些特殊情况下,你可能需要手动关闭连接或使用with语句和requests.Session()来管理连接的打开和关闭。
posted @ 2024-06-05 18:31  abloger  阅读(156)  评论(0编辑  收藏  举报