• Python网络爬虫学习总结


     1、检查robots.txt

    让爬虫了解爬取该网站时存在哪些限制。

    最小化爬虫被封禁的可能,而且还能发现和网站结构相关的线索。

    2、检查网站地图(robots.txt文件中发现的Sitemap文件)

    帮助爬虫定位网站最新的内容,而无须爬取每一个网页。

    网站地图提供了所有网页的链接,我们仍需对其谨慎处理,因为该文件经常存在缺失、过期或者不完整的问题。

    3、估算网站大小

    爬取效率(使用分布式)

    方法:检查Google爬虫的结果(Google中搜索site:www.xxxxx.com/xxxxxx)

    4、识别网站所用技术

    builtwith模块

    builtwith.parse(‘http://www.xxxxx.com’)

    • Web2py框架、通用JavaScript:内容嵌入在HTML中,容易抓取
    • AngularJS:动态加载
    • ASP.NET:会话管理和表单提交

    5、寻找网站所有者

    WHOIS协议查询域名的注册者

    python-whois包

    6、下载网页

    urllib2模块(urllib模块)

    urllib2.urlopen(url).read()

    7、重试下载

    4xx错误发生在请求存在问题时,5xx错误发生在服务端存在问题时。

    5xx错误时重试下载。

    num_retries 设定重试下载的次数

    urllib2.URLError as e
    e.reason
    hasattr(e, ‘code’) and 500 <= e.code <600

    8、设置用户代理

    因为曾经历过质量不佳的Python网络爬虫造成的服务器过载,一些网站还会封禁这个默认的用户代理(Python-urllib/2.7)

    user_agent = ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36’
    headers = {‘User-agent’: user_agent}
    urllib2.Request(url, headers=headers)

    9、解析robots.txt

    robotparser模块

    rp = rebotparser.RobotFileParser()
    rp.set_url(url)
    rp.read()
    rp.can_fetch(user_agent, url)

    10、支持代理(FQ)

    proxy = ’121.193.143.249:80’
    opener = urllib2.build_opener()
    proxy_params = {urlparse.urlparse(url).scheme: proxy}
    opener.add_handler(urllib2.ProxyHandler(proxy_params))
    response = opener.open(request)

    11、下载限速

    self.delay:延时限速

    domain = urlparse.urlparse(url).netloc # 获取domain
    last_accessed = self.domains.get(domain)
    if self.delay > 0 and last_accessed is not None:
        sleep_secs = self.delay - (datetime.now() - last_accessed).seconds
        if sleep_secs > 0:
            time.sleep(sleep_secs)
    self.domains[domain] = datetime.now()

    12、避免爬虫陷阱

    深度 depth

    最大深度 max_depth

    max_depth = 2
    seen = {}
    depth = seen[url]
    if depth != max_depth:
        for link in links:
            if link not in seen:
                seen[link] = depth + 1
                crawl_queue.append(link)

    13、链接转换为绝对链接

    urlparse模块

    urlparse.urljoin(seed_url, link)

    14、三种网页抓取方法

    正则表达式:re.findall()

    Beautiful Soup:

    beautifulsoup4模块

    soup = BeautifulSoup(html, ‘html.parser’)
    soup.find()

    Lxml:

    lxml.html模块

    tree = lxml.html.fromstring(html)
    tree.cssselect()

    15、磁盘缓存

    • pickle(输入转化为字符串)
    • zlib(压缩序列化字符串)
    • shutil(高层次的文件操作工具)
    • datetime(过期)
    • urlparse(文件名urlparse.urlsplit分割URL)

    16、NoSQL

    • 列数据存储(HBase)
    • 键值对存储(Redis)
    • 面向文档的数据库(MongoDB)
    • 图形数据库(Neo4j)

    17、数据库缓存

    self.client = MongoClient('localhost', 27017) if client is None else client
    self.db = self.client.cache
    expires=timedelta(days=30)
    self.db.webpage.create_index('timestamp', expireAfterSeconds=expires.total_seconds())

    set方法:

    from bson.binary import Binary # 二进制形式存储
    record = {'result': Binary(zlib.compress(pickle.dumps(result))), 'timestamp': datetime.utcnow()}
    self.db.webpage.update({'_id': url}, {'$set': record}, upsert=True)

    get方法:

    record = self.db.webpage.find_one({'_id': url})
    pickle.loads(zlib.decompress(record['result']))

    18、多线程爬虫

    threads = []
    while threads or crawl_queue:
        for thread in threads:
            if not thread.is_alive():
                threads.remove(thread)
        while len(threads) < max_threads and crawl_queue:
            thread = threading.Thread(target=process_queue)
            thread.setDaemon(True) # set daemon so main thread can exit when receives ctrl-c
            thread.start()
            threads.append(thread)
      time.sleep(SLEEP_TIME)

    19、多进程爬虫

    def process_crawler(args, **kwargs):
        num_cpus = multiprocessing.cpu_count()
        #pool = multiprocessing.Pool(processes=num_cpus)
        print 'Starting {} processes'.format(num_cpus)
        processes = []
        for i in range(num_cpus):
            p = multiprocessing.Process(target=threaded_crawler, args=[args], kwargs=kwargs)
            #parsed = pool.apply_async(threaded_link_crawler, args, kwargs)
            p.start()
            processes.append(p)
        # wait for processes to complete
        for p in processes:
            p.join()

    20、动态网页进行逆向工程

    ajax请求数据(数据接口API)

    json解析成一个字典

    21、渲染动态网页

    • WebKit渲染引擎(通过Qt框架可以获得该引擎的一个便捷Python接口)
    • Selenium(一个用于Web应用程序测试的工具)
    • PhantomJS(提供一个浏览器环境的命令行接口,你可以把它看作一个“虚拟浏览器”,除了不能浏览,其他与正常浏览器一样)

    难点:需要等待AJAX请求完成之后才能加载结果,定义wait

    22、表单交互

    发送POST请求提交表单(重要部分cookie,cookie是网站在HTTP响应头中传输的少量数据)

    def parse_form(html):
        tree = lxml.html.fromstring(html)
        data = {}
        for e in tree.cssselect('form input'):
            if e.get('name'):
                data[e.get('name')] = e.get('value')
      return data
    data = parse_form(html)
    data['email'] = LOGIN_EMAIL
    data['password'] = LOGIN_PASSWORD
    encoded_data = urllib.urlencode(data)
    request = urllib2.Request(LOGIN_URL, encoded_data)
    response = opener.open(request)

    23、使用cookie登录网站

    cookie是网站在HTTP响应头中传输的少量数据,形如:Set-Cookie: session_id=example;。

    浏览器将会存储这些数据,并在后续对该网站的请求头中包含它们。这样就可以让网站识别和跟踪用户。

    import cookielib
    cj = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
    html = opener.open(LOGIN_URL).read()

    24、从浏览器加载cookie(pprint美观打印数据结构)

    import glob
    import os
    
    # 返回session文件路径的辅助函数
    def find_ff_sessions():
        paths = [
            '~/.mozilla/firefox/*.default',        # Linux系统
            '~/Library/Application Support/Firefox/Profiles/*.default',      # OS X
            '%APPDATA%/Roaming/Mozilla/Firefox/Profiles/*.default'       # Windows Vista及以上版本
        ]
        for path in paths:
            filename = os.path.join(path, 'sessionstore.js')
            matches = glob.glob(os.path.expanduser(filename))
            if matches:
                return matches[0]

    glob模块会返回指定路径中所有匹配的文件。

    # 把session解析到CookieJar对象的函数
    def load_ff_sessions(session_filename):
        cj = cookielib.CookieJar()
        if os.path.exists(session_filename): 
            try:
                json_data = json.loads(open(session_filename, 'rb').read())
            except ValueError as e:
                print 'Error parsing session JSON:', str(e)
            else:
                for window in json_data.get('windows', []):
                    for cookie in window.get('cookies', []):
                        import pprint; pprint.pprint(cookie)
                        c = cookielib.Cookie(0, cookie.get('name', ''), cookie.get('value', ''),
                            None, False,
                            cookie.get('host', ''), cookie.get('host', '').startswith('.'), cookie.get('host', '').startswith('.'),
                            cookie.get('path', ''), False,
                            False, str(int(time.time()) + 3600 * 24 * 7), False,
                            None, None, {})
                        cj.set_cookie(c)
        else:
            print 'Session filename does not exist:', session_filename
        return cj

    最后我们只需要使用浏览器cookie登录:

    session_filename = find_ff_sessions()
    cj = load_ff_sessions(session_filename)
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
    html = opener.open(URL).read()

    25、自动化表单处理(Mechanize--mechanize only works on python 2.x)

    简化表单提交的高级模块Mechanize

    不再需要管理cookie,而且访问表单输入框也更加容易。

    import mechanize
    br = mechanize.Browser()
    br.open(login.LOGIN_URL)
    br.select_form(nr=0)
    br['email'] = login.LOGIN_EMAIL
    br['password'] = login.LOGIN_PASSWORD
    response = br.submit()

    26、验证码处理(光学字符识别(COR)运用在验证码像素基本一致、字体标准、限制在字典中的单词)

    from io import BytesIO
    import lxml.html
    from PIL import Image
    
    # 返回包含验证码图像的Image对象
    def extract_image(html):
        tree = lxml.html.fromstring(html)
        img_data = tree.cssselect('div#recaptcha img')[0].get('src')
        # remove data:image/png;base64, header
        img_data = img_data.partition(',')[-1]
        #open('test_.png', 'wb').write(data.decode('base64'))
        binary_img_data = img_data.decode('base64')
        file_like = BytesIO(binary_img_data)
        img = Image.open(file_like)
        #img.save('test.png')
        return img
    import pytesseract
    
    # 阈值化,抽取验证码中的文本
    def ocr(img):
        gray = img.convert('L')
        bw = gray.point(lambda x: 0 if x < 1 else 255, '1')
        word = pytesseract.image_to_string(bw)
        ascii_word = ''.join(c for c in word if c in string.letters).lower()
        return ascii_word

    27、处理复杂验证码(验证码处理API)

    • 2captcha.com
    • deathbycaptcha.com
    • 9kw.eu(可以不需要花钱)

    28、Scrapy(一个流行的网络爬虫框架,可保存结果、中断恢复爬虫)

    Scrapy拥有很多简化网站抓取的高级函数

    scrapy -h 查看命令的详细信息

    1. startproject:创建一个新项目
    2. genspider:根据模板生成一个新爬虫
    3. crawl:执行爬虫
    4. shell:启动交互式抓取控制台

    29、Portia(一款基于Scrapy开发的开源工具)

    该工具可以通过点击要抓取的网站部分来创建爬虫,这样就比手工创建CSS选择器的方式更加方便。

    30、Scrapely库

    使用训练数据建立从网页中抓取哪些内容的模型,并在以后抓取相同结构的其他网页时应用该模型。

    from scrapely import Scraper
    
    s = Scraper()
    train_url = ‘http://www.xxxxx.com/xxxxxx’
    s.train(train_url, {‘name’: ‘xxx’, ‘population’: ‘xxxx’})
    test_url = ‘xxxxxxx’
    s.scrape(test_url)

    网页内容是静态的,在布局发生改变时,这种方法就会非常有用。

    31、反爬虫

    为什么?

    1. 爬虫占总PV比例较高,这样浪费钱(尤其是三月份爬虫)。
    2. 公司可免费查询的资源被批量抓走,丧失竞争力,这样少赚钱。
    3. 爬虫是否涉嫌违法? 如果是的话,是否可以起诉要求赔偿?这样可以赚钱。

    怎么做?

    • 后台对访问进行统计,如果单个IP或userAgent访问超过阈值,予以封锁。
    • 验证码、Ajax异步加载、Noscript标签的使用、Cookie限制
  • 相关阅读:
    将文本文档数据导入excel,并生产折线
    worktile 查询已归档任务
    TestFlight下载app 初使用
    app测试之app启动时间计算
    MAC 鼠标没电了,键盘命令行关机
    git和adb安装及常用命令
    max 批量导入obj
    [水煮 ASP.NET Web API2 方法论](3-1)集中式路由
    [水煮 ASP.NET Web API2 方法论](12-4)OData 支持的 Function 和 Action
    [水煮 ASP.NET Web API2 方法论](12-3)OData 查询
  • 原文地址:https://www.cnblogs.com/jacen789/p/8819614.html
Copyright © 2020-2023  润新知