天天看点

scrapy-redis插件爬取示例

爬取新闻新浪页面

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

<code>items.py</code>

<code>import</code> <code>scrapy</code>

<code>class</code> <code>SinaItem(scrapy.Item):</code>

<code>    </code><code># define the fields for your item here like:</code>

<code>    </code><code># name = scrapy.Field()</code>

<code>    </code><code>pass</code>

<code>class</code> <code>SinanewsItem(scrapy.Item):</code>

<code>    </code><code>#大类的标题和url</code>

<code>    </code><code>parentTitle </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>parentUrls </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>#小类的标题和子url</code>

<code>    </code><code>subTitle </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>subUrls </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>#小类目录存储路径</code>

<code>    </code><code>subFilename </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>#小类下的子链接</code>

<code>    </code><code>sonUrl </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>#文章标题和内容</code>

<code>    </code><code>head </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code><code>content </code><code>=</code> <code>scrapy.Field()</code>

<code>    </code> 

<code>爬虫脚本sina01.py</code>

<code># -*- coding: utf-8 -*-</code>

<code>from</code> <code>..items </code><code>import</code> <code>SinanewsItem</code>

<code>from</code> <code>scrapy_redis.spiders </code><code>import</code> <code>RedisSpider</code>

<code>class</code> <code>Sina01Spider(RedisSpider):</code>

<code>    </code><code>name </code><code>=</code> <code>'sina01'</code>

<code>    </code><code>#启动爬虫时的命令</code>

<code>    </code><code>redis_key </code><code>=</code> <code>"sinaspider:start_urls"</code>

<code>    </code><code>#allowed_domains = ['sina.com']</code>

<code>    </code><code># start_urls = ['http://sina.com/']</code>

<code>    </code><code>#动态定义爬虫取域范围</code>

<code>    </code><code>def</code> <code>__init__(</code><code>self</code><code>, </code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kwargs):</code>

<code>        </code><code>domain </code><code>=</code> <code>kwargs.pop(</code><code>'domain'</code><code>, '')</code>

<code>        </code><code>self</code><code>.allowed_domains </code><code>=</code> <code>filter</code><code>(</code><code>None</code><code>, domain.split(</code><code>','</code><code>))</code>

<code>        </code><code>super</code><code>(Sina01Spider, </code><code>self</code><code>).__init__(</code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kwargs)</code>

<code>    </code><code>def</code> <code>parse(</code><code>self</code><code>, response):</code>

<code>        </code><code>items </code><code>=</code> <code>[]</code>

<code>        </code><code>#所有大类的url和标题</code>

<code>        </code><code>parentUrls </code><code>=</code> <code>response.xpath(</code><code>'//div[@id="tab01"]/div/h3/a/@href'</code><code>).extract()</code>

<code>        </code><code>parentTitle </code><code>=</code> <code>response.xpath(</code><code>'//div[@id="tab01"]/div/h3/a/text()'</code><code>).extract()</code>

<code>        </code><code>#所有小类的url和标题</code>

<code>        </code><code>subUrls </code><code>=</code> <code>response.xpath(</code><code>'//div[@id="tab01"]/div/ul/li/a/@href'</code><code>).extract()</code>

<code>        </code><code>subTitle </code><code>=</code> <code>response.xpath(</code><code>'//div[@id="tab01"]/div/ul/li/a/text()'</code><code>).extract()</code>

<code>        </code><code>#爬取所有大类</code>

<code>        </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>0</code><code>, </code><code>len</code><code>(parentTitle)):</code>

<code>            </code><code>#爬取所有小类</code>

<code>            </code><code>for</code> <code>j </code><code>in</code> <code>range</code><code>(</code><code>0</code><code>, </code><code>len</code><code>(subUrls)):</code>

<code>                </code><code>item </code><code>=</code> <code>SinanewsItem()</code>

<code>                </code><code>#保存大类的title和urls</code>

<code>                </code><code>item[</code><code>'parentTitle'</code><code>] </code><code>=</code> <code>parentTitle[i]</code>

<code>                </code><code>item[</code><code>'parentUrls'</code><code>] </code><code>=</code> <code>parentUrls[i]</code>

<code>                </code><code>#检查小类的url是否以同类别大类url开头,如果是返回True</code>

<code>                </code><code>if_belong </code><code>=</code> <code>subUrls[j].startswith(item[</code><code>'parentUrls'</code><code>])</code>

<code>                </code><code>if</code> <code>(if_belong):</code>

<code>                    </code><code># 存储小类url、title和filename字段数据</code>

<code>                    </code><code>item[</code><code>'subUrls'</code><code>] </code><code>=</code> <code>subUrls[j]</code>

<code>                    </code><code>item[</code><code>'subTitle'</code><code>] </code><code>=</code> <code>subTitle[j]</code>

<code>                    </code><code>items.append(item)</code>

<code>        </code><code># 发送每个小类url的Request请求,得到Response连同包含meta数据 一同交给回调函数 second_parse 方法处理</code>

<code>        </code><code>for</code> <code>item </code><code>in</code> <code>items:</code>

<code>            </code><code>yield</code> <code>scrapy.Request(url</code><code>=</code><code>item[</code><code>'subUrls'</code><code>], meta</code><code>=</code><code>{</code><code>'meta_1'</code><code>:item}, callback</code><code>=</code><code>self</code><code>.second_parse)</code>

<code>    </code><code>#对于返回的小类的url,在进行递归请求</code>

<code>    </code><code>def</code> <code>second_parse(</code><code>self</code><code>, response):</code>

<code>        </code><code>#提取每次Response的meta数据</code>

<code>        </code><code>meta_1 </code><code>=</code> <code>response.meta[</code><code>'meta_1'</code><code>]</code>

<code>        </code><code>#取出小类的所有子链接</code>

<code>        </code><code>sonUrls </code><code>=</code> <code>response.xpath(</code><code>'//a/@href'</code><code>).extract()</code>

<code>        </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>0</code><code>, </code><code>len</code><code>(sonUrls)):</code>

<code>            </code><code>#检查每个链接是否以大类url开头、以.shtml结尾,如果是返回True</code>

<code>            </code><code>if_belong </code><code>=</code> <code>sonUrls[i].endswith(</code><code>'.shtml'</code><code>) </code><code>and</code> <code>sonUrls[i].startwith(meta_1[parentUrls])</code>

<code>            </code><code># 如果属于本大类,获取字段值放在同一个item下便于传输</code>

<code>            </code><code>if</code><code>(if_belong):</code>

<code>                </code><code>item[</code><code>'parentTitle'</code><code>] </code><code>=</code> <code>meta_1[</code><code>'parentTitle'</code><code>]</code>

<code>                </code><code>item[</code><code>'parentUrls'</code><code>] </code><code>=</code> <code>meta_1[</code><code>'parentUrls'</code><code>]</code>

<code>                </code><code>item[</code><code>'subUrls'</code><code>] </code><code>=</code> <code>meta_1[</code><code>'subUrls'</code><code>]</code>

<code>                </code><code>item[</code><code>'subTitle'</code><code>] </code><code>=</code> <code>meta_1[</code><code>'subTitle'</code><code>]</code>

<code>                </code><code>item[</code><code>'sonUrls'</code><code>] </code><code>=</code> <code>sonUrls[i]</code>

<code>                </code><code>items.append(item)</code>

<code>        </code><code># 发送每个小类下子链接url的Request请求,得到Response后连同包含meta数据 一同交给回调函数 detail_parse 方法处理</code>

<code>            </code><code>yield</code> <code>scrapy.Request(url</code><code>=</code><code>item[</code><code>'sonUrls'</code><code>],meta</code><code>=</code><code>{</code><code>'meta_2'</code><code>:item},callback</code><code>=</code><code>self</code><code>.detail_parse)</code>

<code>        </code><code>#数据解析方法,获取文章标题和内容</code>

<code>        </code><code>def</code> <code>detail_parse(</code><code>self</code><code>, response):</code>

<code>            </code><code>item </code><code>=</code> <code>response.meta[</code><code>'meta_2'</code><code>]</code>

<code>            </code><code>content </code><code>=</code> <code>""</code>

<code>            </code><code>head </code><code>=</code> <code>response.xpath(</code><code>'/h1[@id="main_title"]/text()'</code><code>)</code>

<code>            </code><code>content_list </code><code>=</code> <code>response.xpath(</code><code>'//div[@id="artibody"]/p/text()'</code><code>).extract()</code>

<code>            </code><code>#将p标签里的文本内容 合并到一起</code>

<code>            </code><code>for</code> <code>content_one </code><code>in</code> <code>content_list:</code>

<code>                </code><code>content </code><code>+</code><code>=</code> <code>content_one</code>

<code>            </code><code>item[</code><code>'head'</code><code>] </code><code>=</code> <code>head[</code><code>0</code><code>] </code><code>if</code> <code>len</code><code>(head) &gt; </code><code>0</code> <code>else</code> <code>"NULL"</code>

<code>            </code><code>item[</code><code>'content'</code><code>] </code><code>=</code> <code>content</code>

<code>            </code><code>yield</code> <code>item</code>

<code>            </code> 

<code> </code><code>settings.py添加</code>

<code> </code><code># 使用scrapy-redis里的去重组件,不使用scrapy默认的去重方式</code>

<code>DUPEFILTER_CLASS </code><code>=</code> <code>"scrapy_redis.dupefilter.RFPDupeFilter"</code>

<code># 使用scrapy-redis里的调度器组件,不使用默认的调度器</code>

<code>SCHEDULER </code><code>=</code> <code>"scrapy_redis.scheduler.Scheduler"</code>

<code># 允许暂停,redis请求记录不丢失</code>

<code>SCHEDULER_PERSIST </code><code>=</code> <code>True</code>

<code># 默认的scrapy-redis请求队列形式(按优先级)</code>

<code>SCHEDULER_QUEUE_CLASS </code><code>=</code> <code>"scrapy_redis.queue.SpiderPriorityQueue"</code>

<code># 队列形式,请求先进先出</code>

<code>#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"</code>

<code># 栈形式,请求先进后出</code>

<code>#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"</code>

<code># 只是将数据放到redis数据库,不需要写pipelines文件</code>

<code>ITEM_PIPELINES </code><code>=</code> <code>{</code>

<code>#    'Sina.pipelines.SinaPipeline': 300,</code>

<code>    </code><code>'scrapy_redis.pipelines.RedisPipeline'</code><code>: </code><code>400</code><code>,</code>

<code>}</code>

<code># LOG_LEVEL = 'DEBUG'</code>

<code># Introduce an artifical delay to make use of parallelism. to speed up the</code>

<code># crawl.</code>

<code>DOWNLOAD_DELAY </code><code>=</code> <code>1</code>

<code># 指定数据库的主机IP</code>

<code>REDIS_HOST </code><code>=</code> <code>"localhost"</code>

<code># 指定数据库的端口号</code>

<code>REDIS_PORT </code><code>=</code> <code>6379</code> 

<code>打开redis客户端添加url测试</code>

<code>lpush sinaspider:start_urls http:</code><code>/</code><code>/</code><code>news.sina.com.cn</code><code>/</code><code>guide</code><code>/</code>

     本文转自小白的希望 51CTO博客,原文链接:http://blog.51cto.com/haoyonghui/1978095,如需转载请自行联系原作者