Python爬虫

Python爬虫解决生活问题

Posted by CHY on October 19, 2020

紧跟着《生信修炼手册》的步伐,开始学习了解Python爬虫开发,为后续打下基础。

网络爬虫流程:

  1. 网页内容下载
    1. urllib、request、selenium
  2. html内容清洗
    1. 正则表达式、xpath表达式、beautifulsoup
  3. 数据库内容存储
    1. sqlite、mysql、monogodb 爬虫进阶路径

用户代理在爬虫中的应用

用户代理(User-Agent),其具体内容为一行字符串,用来表征操作系统,浏览器版本等信息。
通过修改http请求中的user-agent信息,可以将普通的爬虫程序伪装成一个浏览器的请求,从而绕过服务器反爬虫机制中对user-agent的限制。

# urllib模块中设定UA
headers = {
     'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

IP代理在网络爬虫中的应用

通过用户代理可以将普通的爬虫程序伪装成浏览器,而IP代理的作用则是用于突破目标服务器对同一IP访问频率的限制。
在python中,通过urllib和requests这两个模块都实现IP代理。

## urllib  检测IP可行性
proxy="http://119.8.44.244:8080"
 proxy_support=urllib.request.ProxyHandler({'http':proxy})
opener = urllib.request.build_opener(proxy_support)
urllib.request.install_opener(opener)
r = urllib.request.urlopen('http://icanhazip.com')
r.read()
## requests  检测IP可行性
import requests
proxies = {'http':'http://119.8.44.244:8080'}
r=requests.get("http://icanhazip.com", proxies=proxies)
r.text
## 完整流程
import requests
import random
import threading

# 获取代理IP
def get_proxy():
    ip_list = [
        'http://197.231.196.44:42461',
        'http://190.124.164.78:8080',
        'http://87.117.169.23:48705',
    ]
     return random.choice(ip_list)

# 下载单个网页
def getHtml(url, proxy):
    retry_count = 5
    while retry_count > 0:
        try:
            html = requests.get(url, proxies= {'http':proxy})
            return html
        except Exception:
            retry_count -= 1
    return None

# 每个线程的处理逻辑
def download_html(ko, semaphore, proxy):
    semaphore.acquire()
    url = 'https://www.genome.jp/dbget-bin/www_bget?ko:{}'.format(ko)
    out = './{}.kgml'.format(ko)
    r = getHtml(url, proxy)
    if r:
        print('{} download success!'.format(ko))
        with open(out, 'w') as fp:
            fp.write(r.text)
    else:
      print('{} download failed!'.format(ko))
    semaphore.release()

if __name__ == '__main__':
    ko_list = ['K{:05d}'.format(i) for i in range(1, 201)]

    thread_list = []
    semaphore = threading.BoundedSemaphore(100)
    for cnt, ko in enumerate(ko_list):
        if cnt % 10 == 0:
            proxy = get_proxy()
        p = threading.Thread(target = download_html, args = (ko, semaphore, proxy ))
        p.start()
        thread_list.append(p)
        
    for thread in thread_list:
        thread.join()

cookie在网络爬虫中的应用

主要用于解决需要登录的网页的问题。ookie是一种存储在本地浏览器中的用户认证信息。一般使用F12查看。
cookie是一个动态信息,是和服务器交互之后生成的,具有时效性,在有效期内,cookie可以保持用户的登录状态,避免重复登录。当我们手动重新登录时,可以看到cookie的信息发生了变化.

# urllib模块中的用法
headers = {
...   'Cookie': 'sessionid=feli4ngf23njptxxb0qma5tl04x8wc43; csrftoken=O9YSm7TMaIb2ZdqEnENJY1GBXj3xUE26',
...   'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
... }
request = urllib.request.Request('http://www.test.com', headers = headers)
response = urllib.request.urlopen(request)
# requests模块中的用法
import requests
headers = {
...   'Cookie': 'sessionid=feli4ngf23njptxxb0qma5tl04x8wc43; csrftoken=O9YSm7TMaIb2ZdqEnENJY1GBXj3xUE26',
...   'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
... }
r = requests.get('http://www.test.com', headers=headers)
# 模拟登录
import urllib.request
import http.cookiejar
url = 'http://www.test.com'
user = 'user'
password = 'passwd'
# 账号,密码的验证
pwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
pwdmgr.add_password(None, url, user, password)
auth_handler = urllib.request.HTTPBasicAuthHandler(pwdmgr)
# cookie处理
cookies = http.cookiejar.CookieJar()
cookie_handler = urllib.request.HTTPCookieProcessor(cookies)
# 构建opener
opener = urllib.request.build_opener(auth_handler, cookie_handler)
# 安装为全局
urllib.request.install_opener(opener)
r = urllib.request.urlopen(url)
for item in cookies:
... print(item.name+'='+item.value)

动态网页常用的两种数据加载方式ajax和js动态请求

ajax请求通过network选项中的xhr请求来查找;js请求通过network选项中的js请求来进行查找。

使用selenium自动化操作浏览器

selenium是一个浏览器自动测试工具,通过驱动程序来自动化操作对应的浏览器,包括了打开浏览器窗口,定位元素,点击按钮,上传文件等操作。巧妙回避普通爬虫程序遇到的动态页面解析的难点。

# 具体示例,打开百度网页及关闭
from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get('https://www.baidu.com')
browser.close()

常见功能:
定位元素

  1. find_element_by_id
  2. find_element_by_name
  3. find_element_by_xpath
  4. find_element_by_link_text
  5. find_element_by_partial_link_text
  6. find_element_by_tag_name
  7. find_element_by_class_name
  8. find_element_by_css_selector 操作元素
  9. send_keys, 填写文本框或者上传文件
  10. submit, 提交表单
  11. select_by_index, 选择下拉列表
  12. save_screenshot, 保存网页截图

使用BeautifulSoup解析网页内容

# 解析html和xml文档内容,构建对象
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')

# 常规多用lxm解析器 -- 最终得到一个文档树

# 1. 访问标签
soup = BeautifulSoup(html_doc, 'lxml')
soup.head
soup.head.title
soup.a     # 默认只会返回文档的第一个标签
soup.find_all("a")   # 返回多个标签构成的列表
soup.find_all("a")[0]
# find方法添加过滤条件,精确定位
# 通过text进行筛选
soup.find_all('a',text='Elsie')
# 通过属性和值进行筛选
soup.find_all('a',attrs=['id','link1'])
# CSS选择器
soup.find_all('p',class_='title')

# 2. 访问标签内容和属性
# name和string可以访问标签的名字和内容
# get和中括号操作符则可以访问标签中的属性和值
soup.a['class']
soup.a.get('class')
soup.a.get('class')
soup.a.name
soup.a.string

xpath语法 – 提取网页信息

# 通过lxml模块来使用xpath
from lxml import etree
html = etree.parse("K00001.html", etree.HTMLParser())
html.xpath('/html')

# 绝对定位,用/表示,选取路径树中直接相连的子节点
# 相对定位,用//表示,表示路径树中所有的子孙节点
# 从根节点开始,依次指定路径
html.xpath('/html/head/title')
# 利用//符号,得到属于html标签孙节点的title标签
html.xpath('/html//title')
#  直接用//符号,捕获title标签
html.xpath('//title')

## 利用位置筛选
html.xpath('//link')
html.xpath('//link[1]')
html.xpath('//link[last()]')
html.xpath('//link[position() < 3]')

# 利用属性筛选
html.xpath('//link[@media]')
html.xpath('//link[@media = "only"]')
html.xpath('//link[@media = "only" and @herf="#"]')

## 获取对应信息
html.xpath('//title/text()')
html.xpath('//a/@href')