import gensim import jieba import numpy as np from scipy.linalg import norm
model_file = './word2vec/news_12g_baidubaike_20g_novel_90g_embedding_64.bin' model = gensim.models.KeyedVectors.load_word2vec_format(model_file, binary=True)
defvector_similarity(s1, s2): defsentence_vector(s): words = jieba.lcut(s) v = np.zeros(64) for word in words: v += model[word] v /= len(words) return v v1, v2 = sentence_vector(s1), sentence_vector(s2) return np.dot(v1, v2) / (norm(v1) * norm(v2))
# If these values are missing, it means we want to use the defaults. optional = { # TODO: Use custom prefixes for this settings to note that are # specific to scrapy-redis. 'queue_key': 'SCHEDULER_QUEUE_KEY', 'queue_cls': 'SCHEDULER_QUEUE_CLASS', 'dupefilter_key': 'SCHEDULER_DUPEFILTER_KEY', # We use the default setting name to keep compatibility. 'dupefilter_cls': 'DUPEFILTER_CLASS', 'serializer': 'SCHEDULER_SERIALIZER', } # 从setting中获取配置组装成dict(具体获取那些配置是optional字典中key) for name, setting_name in optional.items(): val = settings.get(setting_name) if val: kwargs[name] = val
# Support serializer as a path to a module. if isinstance(kwargs.get('serializer'), six.string_types): kwargs['serializer'] = importlib.import_module(kwargs['serializer']) # 或得一个Redis连接 server = connection.from_settings(settings) # Ensure the connection is working. server.ping()
return cls(server=server, **kwargs)
@classmethod def from_crawler(cls, crawler): instance = cls.from_settings(crawler.settings) # FIXME: for now, stats are only supported from this constructor instance.stats = crawler.stats return instance
def open(self, spider): self.spider = spider
try: # 根据self.queue_cls这个可以导入的类 实例化一个队列 self.queue = load_object(self.queue_cls)( server=self.server, spider=spider, key=self.queue_key % {'spider': spider.name}, serializer=self.serializer, ) except TypeError as e: raise ValueError("Failed to instantiate queue class '%s': %s", self.queue_cls, e)
if self.flush_on_start: self.flush() # notice if there are requests already in the queue to resume the crawl if len(self.queue): spider.log("Resuming crawl (%d requests scheduled)" % len(self.queue))
# 在Redis有序集合中数值越小优先级越高(就是会被放在顶层)所以这个位置是取得 相反数 score = -request.priority # We don't use zadd method as the order of arguments change depending on # whether the class is Redis or StrictRedis, and the option of using # kwargs only accepts strings, not bytes. # ZADD 是添加进有序集合 self.server.execute_command('ZADD', self.key, score, data)
defpop(self, timeout=0): """ Pop a request timeout not support in this queue class 有序集合不支持超时所以就木有使用timeout了 这个timeout就是挂羊头卖狗肉 """ """从有序集合中取出一个Request""" # use atomic range/remove using multi/exec """使用multi的原因是为了将获取Request和删除Request合并成一个操作(原子性的)在获取到一个元素之后 删除它,因为有序集合 不像list 有pop 这种方式啊""" pipe = self.server.pipeline() pipe.multi() # 取出 顶层第一个 # zrange :返回有序集 key 中,指定区间内的成员。0,0 就是第一个了 # zremrangebyrank:移除有序集 key 中,指定排名(rank)区间内的所有成员 0,0也就是第一个了 # 更多请参考Redis官方文档 pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0) results, count = pipe.execute() if results: return self._decode_request(results[0])
logger.info('This is a log info') logger.debug('Debugging') logger.warning('Warning exists') logger.info('Finish')
在这里我们首先引入了 logging 模块,然后进行了一下基本的配置,这里通过 basicConfig 配置了 level 信息和 format 信息,这里 level 配置为 INFO 信息,即只输出 INFO 级别的信息,另外这里指定了 format 格式的字符串,包括 asctime、name、levelname、message 四个内容,分别代表运行时间、模块名称、日志级别、日志内容,这样输出内容便是这四者组合而成的内容了,这就是 logging 的全局配置。 接下来声明了一个 Logger 对象,它就是日志输出的主类,调用对象的 info() 方法就可以输出 INFO 级别的日志信息,调用 debug() 方法就可以输出 DEBUG 级别的日志信息,非常方便。在初始化的时候我们传入了模块的名称,这里直接使用 name 来代替了,就是模块的名称,如果直接运行这个脚本的话就是 main,如果是 import 的模块的话就是被引入模块的名称,这个变量在不同的模块中的名字是不同的,所以一般使用 name 来表示就好了,再接下来输出了四条日志信息,其中有两条 INFO、一条 WARNING、一条 DEBUG 信息,我们看下输出结果:
1 2 3
2018-06-0313:42:43,526 - __main__ - INFO - This is a log info 2018-06-0313:42:43,526 - __main__ - WARNING - Warning exists 2018-06-0313:42:43,526 - __main__ - INFO - Finish
2018-06-0314:53:36,467 - __main__ - INFO - This is a log info 2018-06-0314:53:36,468 - __main__ - WARNING - Warning exists 2018-06-0314:53:36,468 - __main__ - INFO - Finish
2018-06-0315:13:44,895 - __main__ - INFO - This is a log info 2018-06-0315:13:44,947 - __main__ - WARNING - Warning exists 2018-06-0315:13:44,949 - __main__ - INFO - Finish
2018-06-0316:55:56,259 - main - INFO - Main Info 2018-06-0316:55:56,259 - main - ERROR - Main Error 2018-06-0316:55:56,259 - main.core - INFO - Core Info 2018-06-0316:55:56,259 - main.core - ERROR - Core Error
try: result = 5 / 0 except Exception as e: # bad logging.error('Error: %s', e) # good logging.error('Error', exc_info=True) # good logging.exception('Error')
memory:The memory to query; usually the output of an RNN encoder. 即解码时用到的上文信息,维度需要是 [batch_size, max_time, context_dim]。这时我们观察一下父类 _BaseAttentionMechanism 的初始化方法,实现如下:
probability_fn:A callable function which converts the score to probabilities. 计算概率时的函数,必须是一个可调用的函数,默认使用 softmax(),还可以指定 hardmax() 等函数。
score_mask_value:The mask value for score before passing into probability_fn. The default is -inf. Only used if memory_sequence_length is not None. 在使用 probability_fn 计算概率之前,对 score 预先进行 mask 使用的值,默认是负无穷。但这个只有在 memory_sequence_length 参数定义的时候有效。
dtype:The data type for the query and memory layers of the attention mechanism. 数据类型,默认是 float32。
def _bahdanau_score(processed_query, keys, normalize): dtype = processed_query.dtype # Get the number of hidden units from the trailing dimension of keys num_units = keys.shape[2].value or array_ops.shape(keys)[2] # Reshape from [batch_size, ...] to [batch_size, 1, ...] for broadcasting. processed_query = array_ops.expand_dims(processed_query, 1) v = variable_scope.get_variable( "attention_v", [num_units], dtype=dtype) if normalize: # Scalar used in weight normalization g = variable_scope.get_variable( "attention_g", dtype=dtype, initializer=math.sqrt((1. / num_units))) # Bias added prior to the nonlinearity b = variable_scope.get_variable( "attention_b", [num_units], dtype=dtype, initializer=init_ops.zeros_initializer()) # normed_v = g * v / ||v|| normed_v = g * v * math_ops.rsqrt( math_ops.reduce_sum(math_ops.square(v))) return math_ops.reduce_sum(normed_v * math_ops.tanh(keys + processed_query + b), [2]) else: return math_ops.reduce_sum(v * math_ops.tanh(keys + processed_query), [2])
if attention_layer_size is not None: attention_layer_sizes = tuple(attention_layer_size if isinstance(attention_layer_size, (list, tuple)) else (attention_layer_size,)) if len(attention_layer_sizes) != len(attention_mechanisms): raise ValueError("If provided, attention_layer_size must contain exactly one integer per attention_mechanism, saw: %d vs %d" % (len(attention_layer_sizes), len(attention_mechanisms))) self._attention_layers = tuple(layers_core.Dense(attention_layer_size, name="attention_layer", use_bias=False, dtype=attention_mechanisms[i].dtype) for i, attention_layer_size in enumerate(attention_layer_sizes)) self._attention_layer_size = sum(attention_layer_sizes) else: self._attention_layers = None self._attention_layer_size = sum(attention_mechanism.values.get_shape()[-1].value for attention_mechanism in attention_mechanisms) for i, attention_mechanism in enumerate(self._attention_mechanisms): attention, alignments = _compute_attention(attention_mechanism, cell_output, previous_alignments[i], self._attention_layers[i] ifself._attention_layerselse None) alignment_history = previous_alignment_history[i].write(state.time, alignments) if self._alignment_history else()
alignment_history:即是否将之前的 alignments 存储到 state 中,以便于后期进行可视化展示。
Options: --update Update Pipenv & pip to latest. --where Output project home information. --venv Output virtualenv information. --py Output Python interpreter information. --envs Output Environment Variable options. --rm Remove the virtualenv. --bare Minimal output. --completion Output completion (to be eval'd). --man Display manpage. --three / --two Use Python 3/2 when creating virtualenv. --python TEXT Specify which version of Python virtualenv should use. --site-packages Enable site-packages for the virtualenv. --jumbotron An easter egg, effectively. --version Show the version and exit. -h, --help Show this message and exit.
Usage Examples: Create a new project using Python 3.6, specifically: $ pipenv --python 3.6
Install all dependencies for a project (including dev): $ pipenv install --dev
Create a lockfile containing pre-releases: $ pipenv lock --pre
Show a graph of your installed dependencies: $ pipenv graph
Check your installed dependencies for security vulnerabilities: $ pipenv check
Install a local setup.py into your virtual environment/Pipfile: $ pipenv install -e .
Commands: check Checks for security vulnerabilities and against PEP 508 markers provided in Pipfile. graph Displays currently–installed dependency graph information. install Installs provided packages and adds them to Pipfile, or (if none is given), installs all packages. lock Generates Pipfile.lock. open View a given module in your editor. run Spawns a command installed into the virtualenv. shell Spawns a shell within the virtualenv. uninstall Un-installs a provided package and removes it from Pipfile. update Uninstalls all packages, and re-installs package(s) in [packages] to latest compatible versions.
接下来我们首先验证一下当前的项目是没有创建虚拟环境的,调用如下命令:
1
pipenv --venv
结果如下:
1
No virtualenv has been created forthisproject yet!
Warning: the environment variable LANG is not set! We recommend setting this in ~/.profile (or equivalent) for proper expected behavior. Creating a virtualenv for this project… Using /usr/local/bin/python3 tocreate virtualenv… ⠋Running virtualenv with interpreter /usr/local/bin/python3 Using base prefix '/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6' New python executable in /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3.6 Also creating executable in /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python Installing setuptools, pip, wheel...done. Virtualenv location: /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E
实际上这也和 virtualenv 激活的流程一样,也是调用了类似 source venv/bin/activate 方法将这个路径加到全局环境变量最前面,这样就会优先调用该路径下的 python、python3、python3.6 可执行文件了。 这时候我们会发现命令行的样子就变了,前面多了一个 (PipenvTest-VSTVh89E) 的标识,代表当前我们已经切换到了虚拟环境下。 这时我们用 which 或 where 命令查看一下 Python 可执行文件的路径,命令如下:
1 2 3 4 5 6
(PipenvTest-VSTVh89E) CQC-MAC% which python3 /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3 (PipenvTest-VSTVh89E) CQC-MAC% which python3.6 /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python3.6 (PipenvTest-VSTVh89E) CQC-MAC% which python /Users/CQC/.local/share/virtualenvs/PipenvTest-VSTVh89E/bin/python
中文分词,即 Chinese Word Segmentation,即将一个汉字序列进行切分,得到一个个单独的词。表面上看,分词其实就是那么回事,但分词效果好不好对信息检索、实验结果还是有很大影响的,同时分词的背后其实是涉及各种各样的算法的。 中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,需要人为切分。根据其特点,可以把分词算法分为四大类:
最大匹配法(MM)。基本思想是:假设自动分词词典中的最长词条所含汉字的个数为 i,则取被处理材料当前字符串序列中的前 i 个字符作为匹配字段,查找分词词典,若词典中有这样一个 i 字词,则匹配成功,匹配字段作为一个词被切分出来;若词典中找不到这样的一个 i 字词,则匹配失败,匹配字段去掉最后一个汉字,剩下的字符作为新的匹配字段,再进行匹配,如此进行下去,直到匹配成功为止。统计结果表明,该方法的错误率 为 1/169。
逆向最大匹配法(RMM)。该方法的分词过程与 MM 法相同,不同的是从句子(或文章)末尾开始处理,每次匹配不成功时去掉的是前面的一个汉字。统计结果表明,该方法的错误率为 1/245。
SnowNLP: Simplified Chinese Text Processing,可以方便的处理中文文本内容,是受到了 TextBlob 的启发而写的,由于现在大部分的自然语言处理库基本都是针对英文的,于是写了一个方便处理中文的类库,并且和 TextBlob 不同的是,这里没有用 NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字典。GitHub地址:https://github.com/isnowfy/snownlp。
pip3 -V pip 9.0.1 from /usr/local/anaconda3/lib/python3.6/site-packages (python 3.6)
1 2 3 4 5 6 7
which python3 /usr/local/anaconda3/bin/python3 python3 Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 18:10:19) [GCC 7.2.0] on linux Type "help", "copyright", "credits"or"license"for more information. >>>
如果存在之前的旧版本,可以选择先卸载,以免和新的 CUDA 版本产生冲突,在 /usr/local/cuda/bin 目录下有一个 uninstallcuda*.pl 文件,可以直接运行卸载,命令如下:
1
sudo ./uninstall_cuda_*.pl
这样即可将 CUDA 全部卸载。 接下来我们再下载 CUDA 9.0,注意 TensorFlow 1.5 和 1.6 版本依然只是兼容 CUDA 9.0,没有兼容 CUDA 9.1,所以不要下载 9.1,CUDA 9.0 的下载地址是:https://developer.nvidia.com/cuda-90-download-archive,然后依次勾选好系统的版本,如图所示: 这里我们选择 Linux-x86_64-Ubuntu-16.04-runfile 的配置,然后点击 Base Installer 部分的 Download 按钮,下载 CUDA 9.0 安装包。 对应的下载命令是:
The NVIDIA CUDA Toolkit provides command-line and graphical tools for building, debugging and optimizing the performance Do you accept the previously read EULA? accept/decline/quit: accept
Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 384.81? (y)es/(n)o/(q)uit: n
Install the CUDA 9.0 Toolkit? (y)es/(n)o/(q)uit: y
Enter Toolkit Location [ default is /usr/local/cuda-9.0 ]:
Do you want to install a symbolic link at /usr/local/cuda? (y)es/(n)o/(q)uit: y
Install the CUDA 9.0 Samples? (y)es/(n)o/(q)uit: y
Enter CUDA Samples Location [ default is /home/cqc ]:
Installing the CUDA Toolkit in /usr/local/cuda-9.0 ...
最后如果出现这样的提示,就证明 CUDA 安装好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Driver: Not Selected Toolkit: Installed in /usr/local/cuda-9.0 Samples: Installed in /home/cqc, but missing recommended libraries
Please make sure that - PATH includes /usr/local/cuda-9.0/bin - LD_LIBRARY_PATH includes /usr/local/cuda-9.0/lib64, or, add /usr/local/cuda-9.0/lib64 to /etc/ld.so.conf and run ldconfig as root
To uninstall the CUDA Toolkit, run the uninstall script in /usr/local/cuda-9.0/bin
Please see CUDA_Installation_Guide_Linux.pdf in /usr/local/cuda-9.0/doc/pdf for detailed information on setting up CUDA.
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 384.00 is required for CUDA 9.0 functionality to work. To install the driver using this installer, run the following command, replacing <CudaInstaller> with the name of this run file: sudo <CudaInstaller>.run -silent -driver
Linux version 4.4.0-112-generic (buildd@lgw01-amd64-010) (gcc version 5.4.020160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5) ) #135-Ubuntu SMP Fri Jan 1911:48:36 UTC 2018
import re str = '我的个人邮箱是cqc@cuiqingcai.com,个人博客是cuiqingcai.com,个人公众号是进击的Coder' results = re.findall('个人(.*?)是(.*?)(?=,|\Z)', str) for result in results: print(result[0] + ': ' + result[1])
data = tf.constant([1, 2, 3]) x = tf.layers.Input(tensor=data) print(x)
结果如下:
1
Tensor("Const:0", shape=(3,), dtype=int32)
可以看到它可以自动计算出其 shape 和 dtype。
batch_normalization
此方法是批量标准化的方法,经过处理之后可以加速训练速度,其定义在 tensorflow/python/layers/normalization.py,论文可以参考:http://arxiv.org/abs/1502.03167 “Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift”。
deftext2vec(text): """ text to one-hot vector :param text: source text :return: np array """ if len(text) > CAPTCHA_LENGTH: returnFalse vector = np.zeros(CAPTCHA_LENGTH * VOCAB_LENGTH) for i, c in enumerate(text): index = i * VOCAB_LENGTH + VOCAB.index(c) vector[index] = 1 return vector
defvec2text(vector): """ vector to captcha text :param vector: np array :return: text """ ifnot isinstance(vector, np.ndarray): vector = np.asarray(vector) vector = np.reshape(vector, [CAPTCHA_LENGTH, -1]) text = '' for item in vector: text += VOCAB[np.argmax(item)] return text
# generate data x and y for i in range(DATA_LENGTH): text = get_random_text() # get captcha array captcha_array = generate_captcha(text) # get vector vector = text2vec(text) data_x.append(captcha_array) data_y.append(vector)
# write data to pickle if not exists(DATA_PATH): makedirs(DATA_PATH)
x = np.asarray(data_x, np.float32) y = np.asarray(data_y, np.float32) with open(join(DATA_PATH, 'data.pkl'), 'wb') as f: pickle.dump(x, f) pickle.dump(y, f)
# input Layer with tf.variable_scope('inputs'): # x.shape = [-1, 60, 160, 3] x, y_label = iterator.get_next() keep_prob = tf.placeholder(tf.float32, []) y = tf.cast(x, tf.float32) # 3 CNN layers for _ in range(3): y = tf.layers.conv2d(y, filters=32, kernel_size=3, padding='same', activation=tf.nn.relu) y = tf.layers.max_pooling2d(y, pool_size=2, strides=2, padding='same') # y = tf.layers.dropout(y, rate=keep_prob)
# 2 dense layers y = tf.layers.flatten(y) y = tf.layers.dense(y, 1024, activation=tf.nn.relu) y = tf.layers.dropout(y, rate=keep_prob) y = tf.layers.dense(y, VOCAB_LENGTH)
NOTE: While the classes are mutually exclusive, their probabilities need not be. All that is required is that each row of labels is a valid probability distribution. If they are not, the computation of the gradient will be incorrect.
from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from urllib.parse import quote
upstream splash { server 41.159.27.223:8050 weight=4; server 41.159.27.221:8050 weight=2; server 41.159.27.9:8050 weight=2; server 41.159.117.119:8050 weight=1; }
import requests from urllib.parse import quote import re
lua = ''' function main(splash, args) local treat = require("treat") local response = splash:http_get("http://httpbin.org/get") return treat.as_string(response.body) end '''
通过 HAR 的结果可以看到,Splash 执行了整个网页的渲染过程,包括 CSS、JavaScript 的加载等过程,呈现的页面和我们在浏览器中得到的结果完全一致。
那么,这个过程由什么来控制呢?重新返回首页,可以看到实际上是有一段脚本,内容如下:
1 2 3 4 5 6 7 8 9
function main(splash, args) assert(splash:go(args.url)) assert(splash:wait(0.5)) return { html = splash:html(), png = splash:png(), har = splash:har(), } end
这个脚本实际上是用 Lua 语言写的脚本。即使不懂这个语言的语法,但从脚本的表面意思,我们也可以大致了解到它首先调用go()方法去加载页面,然后调用wait()方法等待了一定时间,最后返回了页面的源码、截图和 HAR 信息。
functionmain(splash, args) local example_urls = {"www.baidu.com", "www.taobao.com", "www.zhihu.com"} local urls = args.urls or example_urls local results = {} for index, url inipairs(urls) do local ok, reason = splash:go("http://" .. url) if ok then splash:wait(2) results[url] = splash:png() end end return results end
此属性可以设置图片是否加载,默认情况下是加载的。禁用该属性后,可以节省网络流量并提高网页加载速度。但是需要注意的是,禁用图片加载可能会影响 JavaScript 渲染。因为禁用图片之后,它的外层 DOM 节点的高度会受影响,进而影响 DOM 节点的位置。因此,如果 JavaScript 对图片节点有操作的话,其执行就会受到影响。
functionmain(splash, args) local ok, reason = splash:go{"http://httpbin.org/post", http_method="POST", body="name=Germey"} if ok then return splash:html() end end
functionmain(splash, args) localget_div_count = splash:jsfunc([[ function () { var body = document.body; var divs = body.getElementsByTagName('div'); return divs.length; } ]]) splash:go("https://www.baidu.com") return ("There are %s DIVs"):format( get_div_count()) end
functionmain(splash, args) assert(splash:autoload("https://code.jquery.com/jquery-2.1.3.min.js")) assert(splash:go("https://www.taobao.com")) local version = splash:evaljs("$.fn.jquery") return'JQuery version: ' .. version end
functionmain(splash) local treat = require('treat') assert(splash:go("http://quotes.toscrape.com/")) assert(splash:wait(0.5)) local texts = splash:select_all('.quote .text') local results = {} for index, text inipairs(texts) do results[index] = text.node.innerHTML end return treat.as_array(results) end
这里我们通过 CSS 选择器选中了节点的正文内容,随后遍历了所有节点,将其中的文本获取下来。
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11
SplashResponse: Array[10] 0: "“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”" 1: "“It is our choices, Harry, that show what we truly are, far more than our abilities.”" 2: “There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.” 3: "“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”" 4: "“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”" 5: "“Try not to become a man of success. Rather become a man of value.”" 6: "“It is better to be hated for what you are than to be loved for what you are not.”" 7: "“I have not failed. I've just found 10,000 ways that won't work.”" 8: "“A woman is like a tea bag; you never know how strong it is until it's in hot water.”" 9: "“A day without sunshine is like, you know, night.”"
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait
from selenium import webdriver from selenium.webdriver.common.byimportBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
def get_images(json): if json.get('data'): for item in json.get('data'): title = item.get('title') images = item.get('image_detail') for image in images: yield { 'image': image.get('url'), 'title': title }
def save_image(item): ifnot os.path.exists(item.get('title')): os.mkdir(item.get('title')) try: response = requests.get(item.get('image')) if response.status_code == 200: file_path = '{0}/{1}.{2}'.format(item.get('title'), md5(response.content).hexdigest(), 'jpg') ifnot os.path.exists(file_path): withopen(file_path, 'wb') as f: f.write(response.content) else: print('Already Downloaded', file_path) except requests.ConnectionError: print('Failed to Save Image')
最后,只需要构造一个offset数组,遍历offset,提取图片链接,并将其下载即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
from multiprocessing.pool import Pool
def main(offset): json = get_page(offset) for item in get_images(json): print(item) save_image(item)
GROUP_START = 1 GROUP_END = 20
if __name__ == '__main__': pool = Pool() groups = ([x * 20 for x in range(GROUP_START, GROUP_END + 1)]) pool.map(main, groups) pool.close() pool.join()
db = pymysql.connect(host='localhost', user='root', password='123456', port=3306, db='spiders') cursor = db.cursor() sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, age INT NOT NULL, PRIMARY KEY (id))' cursor.execute(sql) db.close()
html = ''' <div class="wrap"> Hello, World <p>This is a paragraph.</p> </div> ''' from pyquery import PyQuery as pq doc = pq(html) wrap = doc('.wrap') print(wrap.text())
from bs4 import BeautifulSoup soup = BeautifulSoup('<p>Hello</p>', 'lxml') print(soup.p.string)
在后面,Beautiful Soup的用法实例也统一用这个解析器来演示。
4. 基本用法
下面首先用实例来看看Beautiful Soup的基本用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
html = """ <html><head><title>The Dormouse's story</title></head> <body> <pclass="title"name="dromouse"><b>The Dormouse's story</b></p> <pclass="story">Once upon a time there were three little sisters; and their names were <ahref="http://example.com/elsie"class="sister"id="link1"><!-- Elsie --></a>, <ahref="http://example.com/lacie"class="sister"id="link2">Lacie</a> and <ahref="http://example.com/tillie"class="sister"id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <pclass="story">...</p> """ from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.prettify()) print(soup.title.string)
<html> <head> <title> The Dormouse's story </title> </head> <body> <pclass="title"name="dromouse"> <b> The Dormouse's story </b> </p> <pclass="story"> Once upon a time there were three little sisters; and their names were <aclass="sister"href="http://example.com/elsie"id="link1"> <!-- Elsie --> </a> , <aclass="sister"href="http://example.com/lacie"id="link2"> Lacie </a> and <aclass="sister"href="http://example.com/tillie"id="link3"> Tillie </a> ; and they lived at the bottom of a well. </p> <pclass="story"> ... </p> </body> </html> The Dormouse's story
html = """ <html><head><title>The Dormouse's story</title></head> <body> <pclass="title"name="dromouse"><b>The Dormouse's story</b></p> <pclass="story">Once upon a time there were three little sisters; and their names were <ahref="http://example.com/elsie"class="sister"id="link1"><!-- Elsie --></a>, <ahref="http://example.com/lacie"class="sister"id="link2">Lacie</a> and <ahref="http://example.com/tillie"class="sister"id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <pclass="story">...</p> """ from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.title) print(type(soup.title)) print(soup.title.string) print(soup.head) print(soup.p)
运行结果如下:
1 2 3 4 5
<title>The Dormouse's story</title> <class 'bs4.element.Tag'> The Dormouse's story <head><title>The Dormouse's story</title></head> <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
html = """ <html> <head> <title>The Dormouse's story</title> </head> <body> <pclass="story"> Once upon a time there were three little sisters; and their names were <ahref="http://example.com/elsie"class="sister"id="link1"> <span>Elsie</span> </a> <ahref="http://example.com/lacie"class="sister"id="link2">Lacie</a> and <ahref="http://example.com/tillie"class="sister"id="link3">Tillie</a> and they lived at the bottom of a well. </p> <pclass="story">...</p> """
运行结果如下:
1 2 3
['\n Once upon a time there were three little sisters; and their names were\n ', <aclass="sister"href="http://example.com/elsie"id="link1"> <span>Elsie</span> </a>, '\n', <aclass="sister"href="http://example.com/lacie"id="link2">Lacie</a>, ' \n and\n ', <aclass="sister"href="http://example.com/tillie"id="link3">Tillie</a>, '\n and they lived at the bottom of a well.\n ']
html = """ <html> <head> <title>The Dormouse's story</title> </head> <body> <pclass="story"> Once upon a time there were three little sisters; and their names were <ahref="http://example.com/elsie"class="sister"id="link1"> <span>Elsie</span> </a> </p> <pclass="story">...</p> """ from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.a.parent)
运行结果如下:
1 2 3 4 5 6
<pclass="story"> Once upon a time there were three little sisters; and their names were <aclass="sister"href="http://example.com/elsie"id="link1"> <span>Elsie</span> </a> </p>
html = """ <html> <body> <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"> <span>Elsie</span> </a> Hello <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> """ from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print('Next Sibling', soup.a.next_sibling) print('Prev Sibling', soup.a.previous_sibling) print('Next Siblings', list(enumerate(soup.a.next_siblings))) print('Prev Siblings', list(enumerate(soup.a.previous_siblings)))
运行结果如下:
1 2 3 4 5 6 7 8
Next Sibling Hello
Prev Sibling Once upon a time there were three little sisters; and their names were
Next Siblings [(0, '\n Hello\n '), (1, <a class="sister"href="http://example.com/lacie"id="link2">Lacie</a>), (2, ' \n and\n '), (3, <a class="sister"href="http://example.com/tillie"id="link3">Tillie</a>), (4, '\n and they lived at the bottom of a well.\n ')] Prev Siblings [(0, '\n Once upon a time there were three little sisters; and their names were\n ')]
html = """ <html> <body> <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">Bob</a><a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> </p> """ from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print('Next Sibling:') print(type(soup.a.next_sibling)) print(soup.a.next_sibling) print(soup.a.next_sibling.string) print('Parent:') print(type(soup.a.parents)) print(list(soup.a.parents)[0]) print(list(soup.a.parents)[0].attrs['class'])
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11
NextSibling: <class 'bs4.element.Tag'> <aclass="sister" href="http://example.com/lacie" id="link2">Lacie</a> Lacie Parent: <class 'generator'> <pclass="story"> Onceuponatimetherewerethreelittlesisters; and their names were <a class="sister" href="http://example.com/elsie" id="link1">Bob</a><a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> </p> ['story']
for ul in soup.find_all(name='ul'): print(ul.find_all(name='li')) for li in ul.find_all(name='li'): print(li.string)
运行结果如下:
1 2 3 4 5 6 7
[<li class="element">Foo</li>, <liclass="element">Bar</li>, <liclass="element">Jay</li>] Foo Bar Jay [<liclass="element">Foo</li>, <liclass="element">Bar</li>] Foo Bar
import re html=''' <div class="panel"> <div class="panel-body"> <a>Hello, this is a link</a> <a>Hello, this is a link, too</a> </div> </div> ''' from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.find_all(text=re.compile('link')))
运行结果如下:
1
['Hello, this is a link', 'Hello, this is a link, too']
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') for li in soup.select('li'): print('Get Text:', li.get_text()) print('String:', li.string)
运行结果如下:
1 2 3 4 5 6 7 8 9 10
GetText: Foo String: Foo GetText: Bar String: Bar GetText: Jay String: Jay GetText: Foo String: Foo GetText: Bar String: Bar